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