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