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.XMLStreamException;
22 import javax.xml.stream.XMLStreamReader;
23
24 import java.io.IOException;
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 com.ctc.wstx.stax.WstxInputFactory;
33 import org.apache.maven.api.xml.XmlNode;
34 import org.codehaus.plexus.util.xml.pull.MXParser;
35 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
36 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
37
38
39
40
41
42 public class XmlNodeBuilder {
43 private static final boolean DEFAULT_TRIM = true;
44
45 public static XmlNodeImpl build(Reader reader) throws XmlPullParserException, IOException {
46 return build(reader, (InputLocationBuilder) null);
47 }
48
49
50
51
52
53
54
55
56
57 public static XmlNodeImpl build(Reader reader, InputLocationBuilder locationBuilder)
58 throws XmlPullParserException, IOException {
59 return build(reader, DEFAULT_TRIM, locationBuilder);
60 }
61
62 public static XmlNodeImpl build(InputStream is, String encoding) throws XmlPullParserException, IOException {
63 return build(is, encoding, DEFAULT_TRIM);
64 }
65
66 public static XmlNodeImpl build(InputStream is, String encoding, boolean trim)
67 throws XmlPullParserException, IOException {
68 XmlPullParser parser = new MXParser();
69 parser.setInput(is, encoding);
70 return build(parser, trim);
71 }
72
73 public static XmlNodeImpl build(Reader reader, boolean trim) throws XmlPullParserException, IOException {
74 return build(reader, trim, null);
75 }
76
77
78
79
80
81
82
83
84
85
86 public static XmlNodeImpl build(Reader reader, boolean trim, InputLocationBuilder locationBuilder)
87 throws XmlPullParserException, IOException {
88 XmlPullParser parser = new MXParser();
89 parser.setInput(reader);
90 return build(parser, trim, locationBuilder);
91 }
92
93 public static XmlNodeImpl build(XmlPullParser parser) throws XmlPullParserException, IOException {
94 return build(parser, DEFAULT_TRIM);
95 }
96
97 public static XmlNodeImpl build(XmlPullParser parser, boolean trim) throws XmlPullParserException, IOException {
98 return build(parser, trim, null);
99 }
100
101
102
103
104
105
106
107
108
109
110 public static XmlNodeImpl build(XmlPullParser parser, boolean trim, InputLocationBuilder locationBuilder)
111 throws XmlPullParserException, IOException {
112 boolean spacePreserve = false;
113 String name = null;
114 String value = null;
115 Object location = null;
116 Map<String, String> attrs = null;
117 List<XmlNode> children = null;
118 int eventType = parser.getEventType();
119 boolean emptyTag = false;
120 while (eventType != XmlPullParser.END_DOCUMENT) {
121 if (eventType == XmlPullParser.START_TAG) {
122 emptyTag = parser.isEmptyElementTag();
123 if (name == null) {
124 name = parser.getName();
125 location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
126 int attributesSize = parser.getAttributeCount();
127 if (attributesSize > 0) {
128 attrs = new HashMap<>();
129 for (int i = 0; i < attributesSize; i++) {
130 String aname = parser.getAttributeName(i);
131 String avalue = parser.getAttributeValue(i);
132 attrs.put(aname, avalue);
133 spacePreserve = spacePreserve || ("xml:space".equals(aname) && "preserve".equals(avalue));
134 }
135 }
136 } else {
137 if (children == null) {
138 children = new ArrayList<>();
139 }
140 XmlNode child = build(parser, trim, locationBuilder);
141 children.add(child);
142 }
143 } else if (eventType == XmlPullParser.TEXT) {
144 String text = parser.getText();
145 if (trim && !spacePreserve) {
146 text = text.trim();
147 }
148 value = value != null ? value + text : text;
149 } else if (eventType == XmlPullParser.END_TAG) {
150 return new XmlNodeImpl(
151 name,
152 children == null ? (value != null ? value : emptyTag ? null : "") : null,
153 attrs,
154 children,
155 location);
156 }
157 eventType = parser.next();
158 }
159 throw new IllegalStateException("End of document found before returning to 0 depth");
160 }
161
162 public static XmlNodeImpl build(Reader reader, InputLocationBuilderStax locationBuilder) throws XMLStreamException {
163 XMLStreamReader parser = WstxInputFactory.newFactory().createXMLStreamReader(reader);
164 return build(parser, DEFAULT_TRIM, locationBuilder);
165 }
166
167 public static XmlNodeImpl build(XMLStreamReader parser) throws XMLStreamException {
168 return build(parser, DEFAULT_TRIM, null);
169 }
170
171 public static XmlNodeImpl build(XMLStreamReader parser, InputLocationBuilderStax locationBuilder)
172 throws XMLStreamException {
173 return build(parser, DEFAULT_TRIM, locationBuilder);
174 }
175
176 public static XmlNodeImpl build(XMLStreamReader parser, boolean trim, InputLocationBuilderStax locationBuilder)
177 throws XMLStreamException {
178 boolean spacePreserve = false;
179 String lPrefix = null;
180 String lNamespaceUri = null;
181 String lName = null;
182 String lValue = null;
183 Object location = null;
184 Map<String, String> attrs = null;
185 List<XmlNode> children = null;
186 int eventType = parser.getEventType();
187 int lastStartTag = -1;
188 while (eventType != XMLStreamReader.END_DOCUMENT) {
189 if (eventType == XMLStreamReader.START_ELEMENT) {
190 lastStartTag = parser.getLocation().getLineNumber() * 1000
191 + parser.getLocation().getColumnNumber();
192 if (lName == null) {
193 int namespacesSize = parser.getNamespaceCount();
194 lPrefix = parser.getPrefix();
195 lNamespaceUri = parser.getNamespaceURI();
196 lName = parser.getLocalName();
197 location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
198 int attributesSize = parser.getAttributeCount();
199 if (attributesSize > 0 || namespacesSize > 0) {
200 attrs = new HashMap<>();
201 for (int i = 0; i < namespacesSize; i++) {
202 String nsPrefix = parser.getNamespacePrefix(i);
203 String nsUri = parser.getNamespaceURI(i);
204 attrs.put(nsPrefix != null && !nsPrefix.isEmpty() ? "xmlns:" + nsPrefix : "xmlns", nsUri);
205 }
206 for (int i = 0; i < attributesSize; i++) {
207 String aName = parser.getAttributeLocalName(i);
208 String aValue = parser.getAttributeValue(i);
209 String aPrefix = parser.getAttributePrefix(i);
210 if (aPrefix != null && !aPrefix.isEmpty()) {
211 aName = aPrefix + ":" + aName;
212 }
213 attrs.put(aName, aValue);
214 spacePreserve = spacePreserve || ("xml:space".equals(aName) && "preserve".equals(aValue));
215 }
216 }
217 } else {
218 if (children == null) {
219 children = new ArrayList<>();
220 }
221 XmlNode child = build(parser, trim, locationBuilder);
222 children.add(child);
223 }
224 } else if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
225 String text = parser.getText();
226 lValue = lValue != null ? lValue + text : text;
227 } else if (eventType == XMLStreamReader.END_ELEMENT) {
228 boolean emptyTag = lastStartTag
229 == parser.getLocation().getLineNumber() * 1000
230 + parser.getLocation().getColumnNumber();
231 if (lValue != null && trim && !spacePreserve) {
232 lValue = lValue.trim();
233 }
234 return new XmlNodeImpl(
235 lPrefix,
236 lNamespaceUri,
237 lName,
238 children == null ? (lValue != null ? lValue : emptyTag ? null : "") : null,
239 attrs,
240 children,
241 location);
242 }
243 eventType = parser.next();
244 }
245 throw new IllegalStateException("End of document found before returning to 0 depth");
246 }
247
248
249
250
251
252
253 public interface InputLocationBuilder {
254 Object toInputLocation(XmlPullParser parser);
255 }
256
257 public interface InputLocationBuilderStax {
258 Object toInputLocation(XMLStreamReader parser);
259 }
260 }