1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.shared.utils.xml;
20  
21  import javax.annotation.Nonnull;
22  import javax.annotation.WillClose;
23  
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.InputStreamReader;
27  import java.io.Reader;
28  import java.io.UnsupportedEncodingException;
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  import org.apache.maven.shared.utils.xml.pull.XmlPullParserException;
33  import org.xml.sax.Attributes;
34  import org.xml.sax.InputSource;
35  import org.xml.sax.SAXException;
36  import org.xml.sax.XMLReader;
37  import org.xml.sax.helpers.DefaultHandler;
38  
39  
40  
41  
42  public class Xpp3DomBuilder {
43  
44      
45  
46  
47  
48  
49      public static Xpp3Dom build(@WillClose @Nonnull Reader reader) throws XmlPullParserException {
50          return build(reader, false);
51      }
52  
53      
54  
55  
56  
57  
58  
59      public static Xpp3Dom build(@WillClose InputStream is, @Nonnull String encoding) throws XmlPullParserException {
60          return build(is, encoding, false);
61      }
62  
63      
64  
65  
66  
67  
68  
69  
70  
71      @Deprecated
72      public static Xpp3Dom build(@WillClose InputStream is, @Nonnull String encoding, boolean noop)
73              throws XmlPullParserException {
74          try {
75              Reader reader = new InputStreamReader(is, encoding);
76              return build(reader);
77          } catch (UnsupportedEncodingException e) {
78              throw new XmlPullParserException(e);
79          }
80      }
81  
82      
83  
84  
85  
86  
87  
88  
89      @Deprecated
90      public static Xpp3Dom build(@WillClose Reader in, boolean noop) throws XmlPullParserException {
91          try (Reader reader = in) {
92              DocHandler docHandler = parseSax(new InputSource(reader));
93              reader.close();
94              return docHandler.result;
95          } catch (final IOException e) {
96              throw new XmlPullParserException(e);
97          }
98      }
99  
100     private static DocHandler parseSax(@Nonnull InputSource inputSource) throws XmlPullParserException {
101         try {
102             DocHandler ch = new DocHandler();
103             XMLReader parser = createXmlReader();
104             parser.setContentHandler(ch);
105             parser.parse(inputSource);
106             return ch;
107         } catch (IOException e) {
108             throw new XmlPullParserException(e);
109         } catch (SAXException e) {
110             throw new XmlPullParserException(e);
111         }
112     }
113 
114     private static XMLReader createXmlReader() throws SAXException {
115         XMLReader comSunXmlReader = instantiate("com.sun.org.apache.xerces.internal.parsers.SAXParser");
116         if (comSunXmlReader != null) {
117             return comSunXmlReader;
118         }
119 
120         String key = "org.xml.sax.driver";
121         String oldParser = System.getProperty(key);
122         System.clearProperty(key); 
123 
124         try {
125             return org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
126         } finally {
127             if (oldParser != null) {
128                 System.setProperty(key, oldParser);
129             }
130         }
131     }
132 
133     private static XMLReader instantiate(String s) {
134         try {
135             Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass(s);
136             return (XMLReader) aClass.newInstance();
137         } catch (ClassNotFoundException e) {
138             return null;
139         } catch (InstantiationException e) {
140             return null;
141         } catch (IllegalAccessException e) {
142             return null;
143         }
144     }
145 
146     private static class DocHandler extends DefaultHandler {
147         private final List<Xpp3Dom> elemStack = new ArrayList<Xpp3Dom>();
148 
149         private final List<StringBuilder> values = new ArrayList<StringBuilder>();
150 
151         Xpp3Dom result = null;
152 
153         private boolean spacePreserve = false;
154 
155         @Override
156         public void startElement(String uri, String localName, String qName, Attributes attributes)
157                 throws SAXException {
158             spacePreserve = false;
159             Xpp3Dom child = new Xpp3Dom(localName);
160 
161             attachToParent(child);
162             pushOnStack(child);
163 
164             values.add(new StringBuilder());
165 
166             int size = attributes.getLength();
167             for (int i = 0; i < size; i++) {
168                 String name = attributes.getQName(i);
169                 String value = attributes.getValue(i);
170                 child.setAttribute(name, value);
171                 spacePreserve = spacePreserve || ("xml:space".equals(name) && "preserve".equals(value));
172             }
173         }
174 
175         private boolean pushOnStack(Xpp3Dom child) {
176             return elemStack.add(child);
177         }
178 
179         private void attachToParent(Xpp3Dom child) {
180             int depth = elemStack.size();
181             if (depth > 0) {
182                 elemStack.get(depth - 1).addChild(child);
183             }
184         }
185 
186         private Xpp3Dom pop() {
187             int depth = elemStack.size() - 1;
188             return elemStack.remove(depth);
189         }
190 
191         @Override
192         public void endElement(String uri, String localName, String qName) throws SAXException {
193             int depth = elemStack.size() - 1;
194 
195             Xpp3Dom element = pop();
196 
197             
198             Object accumulatedValue = values.remove(depth);
199 
200             if (element.getChildCount() == 0) {
201                 if (accumulatedValue == null) {
202                     element.setValue(""); 
203                 } else {
204                     element.setValue(accumulatedValue.toString());
205                 }
206             }
207 
208             if (depth == 0) {
209                 result = element;
210             }
211         }
212 
213         @Override
214         public void characters(char[] ch, int start, int length) throws SAXException {
215             String text = new String(ch, start, length);
216             appendToTopValue(text);
217         }
218 
219         private void appendToTopValue(String toAppend) {
220             
221             StringBuilder stringBuilder = values.get(values.size() - 1);
222             stringBuilder.append(toAppend);
223         }
224     }
225 }