1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.xml;
20
21 import javax.xml.stream.XMLInputFactory;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamReader;
24
25 import java.io.InputStream;
26 import java.io.Reader;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31
32 import org.apache.maven.api.xml.XmlNode;
33
34
35
36
37
38 public class XmlNodeStaxBuilder {
39 private static final boolean DEFAULT_TRIM = true;
40
41 public static XmlNodeImpl build(InputStream stream, InputLocationBuilderStax locationBuilder)
42 throws XMLStreamException {
43 XMLStreamReader parser = XMLInputFactory.newFactory().createXMLStreamReader(stream);
44 return build(parser, DEFAULT_TRIM, locationBuilder);
45 }
46
47 public static XmlNodeImpl build(Reader reader, InputLocationBuilderStax locationBuilder) throws XMLStreamException {
48 XMLStreamReader parser = XMLInputFactory.newFactory().createXMLStreamReader(reader);
49 return build(parser, DEFAULT_TRIM, locationBuilder);
50 }
51
52 public static XmlNodeImpl build(XMLStreamReader parser) throws XMLStreamException {
53 return build(parser, DEFAULT_TRIM, null);
54 }
55
56 public static XmlNodeImpl build(XMLStreamReader parser, InputLocationBuilderStax locationBuilder)
57 throws XMLStreamException {
58 return build(parser, DEFAULT_TRIM, locationBuilder);
59 }
60
61 public static XmlNodeImpl build(XMLStreamReader parser, boolean trim, InputLocationBuilderStax locationBuilder)
62 throws XMLStreamException {
63 boolean spacePreserve = false;
64 String lPrefix = null;
65 String lNamespaceUri = null;
66 String lName = null;
67 String lValue = null;
68 Object location = null;
69 Map<String, String> attrs = null;
70 List<XmlNode> children = null;
71 int eventType = parser.getEventType();
72 int lastStartTag = -1;
73 while (eventType != XMLStreamReader.END_DOCUMENT) {
74 if (eventType == XMLStreamReader.START_ELEMENT) {
75 lastStartTag = parser.getLocation().getLineNumber() * 1000
76 + parser.getLocation().getColumnNumber();
77 if (lName == null) {
78 int namespacesSize = parser.getNamespaceCount();
79 lPrefix = parser.getPrefix();
80 lNamespaceUri = parser.getNamespaceURI();
81 lName = parser.getLocalName();
82 location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
83 int attributesSize = parser.getAttributeCount();
84 if (attributesSize > 0 || namespacesSize > 0) {
85 attrs = new HashMap<>();
86 for (int i = 0; i < namespacesSize; i++) {
87 String nsPrefix = parser.getNamespacePrefix(i);
88 String nsUri = parser.getNamespaceURI(i);
89 attrs.put(nsPrefix != null && !nsPrefix.isEmpty() ? "xmlns:" + nsPrefix : "xmlns", nsUri);
90 }
91 for (int i = 0; i < attributesSize; i++) {
92 String aName = parser.getAttributeLocalName(i);
93 String aValue = parser.getAttributeValue(i);
94 String aPrefix = parser.getAttributePrefix(i);
95 if (aPrefix != null && !aPrefix.isEmpty()) {
96 aName = aPrefix + ":" + aName;
97 }
98 attrs.put(aName, aValue);
99 spacePreserve = spacePreserve || ("xml:space".equals(aName) && "preserve".equals(aValue));
100 }
101 }
102 } else {
103 if (children == null) {
104 children = new ArrayList<>();
105 }
106 XmlNode child = build(parser, trim, locationBuilder);
107 children.add(child);
108 }
109 } else if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
110 String text = parser.getText();
111 lValue = lValue != null ? lValue + text : text;
112 } else if (eventType == XMLStreamReader.END_ELEMENT) {
113 boolean emptyTag = lastStartTag
114 == parser.getLocation().getLineNumber() * 1000
115 + parser.getLocation().getColumnNumber();
116 if (lValue != null && trim && !spacePreserve) {
117 lValue = lValue.trim();
118 }
119 return new XmlNodeImpl(
120 lPrefix,
121 lNamespaceUri,
122 lName,
123 children == null ? (lValue != null ? lValue : emptyTag ? null : "") : null,
124 attrs,
125 children,
126 location);
127 }
128 eventType = parser.next();
129 }
130 throw new IllegalStateException("End of document found before returning to 0 depth");
131 }
132
133
134
135
136
137
138 public interface InputLocationBuilderStax {
139 Object toInputLocation(XMLStreamReader parser);
140 }
141 }