1
2
3
4 package net.sourceforge.pmd.lang.xml.ast;
5
6 import java.io.IOException;
7 import java.io.Reader;
8 import java.io.StringReader;
9 import java.lang.reflect.Proxy;
10 import java.util.Arrays;
11 import java.util.HashMap;
12 import java.util.LinkedHashSet;
13 import java.util.Map;
14 import java.util.Set;
15
16 import javax.xml.parsers.DocumentBuilder;
17 import javax.xml.parsers.DocumentBuilderFactory;
18 import javax.xml.parsers.ParserConfigurationException;
19
20 import net.sourceforge.pmd.lang.ast.ParseException;
21 import net.sourceforge.pmd.lang.ast.RootNode;
22 import net.sourceforge.pmd.lang.xml.XmlParserOptions;
23
24 import org.apache.commons.io.IOUtils;
25 import org.w3c.dom.Document;
26 import org.w3c.dom.Node;
27 import org.xml.sax.InputSource;
28 import org.xml.sax.SAXException;
29
30 public class XmlParser {
31 protected final XmlParserOptions parserOptions;
32 protected Map<Node, XmlNode> nodeCache = new HashMap<Node, XmlNode>();
33
34 public XmlParser(XmlParserOptions parserOptions) {
35 this.parserOptions = parserOptions;
36 }
37
38 protected Document parseDocument(Reader reader) throws ParseException {
39 nodeCache.clear();
40 try {
41 String xmlData = IOUtils.toString(reader);
42
43 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
44 dbf.setNamespaceAware(parserOptions.isNamespaceAware());
45 dbf.setValidating(parserOptions.isValidating());
46 dbf.setIgnoringComments(parserOptions.isIgnoringComments());
47 dbf.setIgnoringElementContentWhitespace(parserOptions.isIgnoringElementContentWhitespace());
48 dbf.setExpandEntityReferences(parserOptions.isExpandEntityReferences());
49 dbf.setCoalescing(parserOptions.isCoalescing());
50 dbf.setXIncludeAware(parserOptions.isXincludeAware());
51 dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
52 dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
53 DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
54 documentBuilder.setEntityResolver(parserOptions.getEntityResolver());
55 Document document = documentBuilder.parse(new InputSource(new StringReader(xmlData)));
56 DOMLineNumbers lineNumbers = new DOMLineNumbers(document, xmlData);
57 lineNumbers.determine();
58 return document;
59 } catch (ParserConfigurationException e) {
60 throw new ParseException(e);
61 } catch (SAXException e) {
62 throw new ParseException(e);
63 } catch (IOException e) {
64 throw new ParseException(e);
65 }
66 }
67
68 public XmlNode parse(Reader reader) {
69 Document document = parseDocument(reader);
70 return createProxy(document);
71 }
72
73 public XmlNode createProxy(Node node) {
74 XmlNode proxy = nodeCache.get(node);
75 if (proxy != null) {
76 return proxy;
77 }
78
79
80 LinkedHashSet<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
81 interfaces.add(XmlNode.class);
82 if (node instanceof Document) {
83 interfaces.add(RootNode.class);
84 }
85 addAllInterfaces(interfaces, node.getClass());
86
87 proxy = (XmlNode) Proxy.newProxyInstance(XmlParser.class.getClassLoader(),
88 interfaces.toArray(new Class[interfaces.size()]), new XmlNodeInvocationHandler(this, node));
89 nodeCache.put(node, proxy);
90 return proxy;
91 }
92
93 public void addAllInterfaces(Set<Class<?>> interfaces, Class<?> clazz) {
94 interfaces.addAll(Arrays.asList((Class<?>[]) clazz.getInterfaces()));
95 if (clazz.getSuperclass() != null) {
96 addAllInterfaces(interfaces, clazz.getSuperclass());
97 }
98 }
99
100 }