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 return docHandler.result;
106 }
107 finally
108 {
109 IOUtil.close( reader );
110 }
111 }
112
113 private static DocHandler parseSax( @Nonnull InputSource inputSource, boolean trim )
114 throws XmlPullParserException
115 {
116 try
117 {
118 DocHandler ch = new DocHandler( trim );
119 XMLReader parser = createXmlReader();
120 parser.setContentHandler( ch );
121 parser.parse( inputSource );
122 return ch;
123 }
124 catch ( IOException e )
125 {
126 throw new XmlPullParserException( e );
127 }
128 catch ( SAXException e )
129 {
130 throw new XmlPullParserException( e );
131 }
132 }
133
134
135 private static XMLReader createXmlReader()
136 throws SAXException
137 {
138 XMLReader comSunXmlReader = instantiate( "com.sun.org.apache.xerces.internal.parsers.SAXParser" );
139 if ( comSunXmlReader != null )
140 {
141 return comSunXmlReader;
142 }
143
144 String key = "org.xml.sax.driver";
145 String oldParser = System.getProperty( key );
146 System.clearProperty( key );
147
148 try
149 {
150 return org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
151 }
152 finally
153 {
154 if ( oldParser != null )
155 {
156 System.setProperty( key, oldParser );
157 }
158 }
159
160 }
161
162 private static XMLReader instantiate( String s )
163 {
164 try
165 {
166 Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass( s );
167 return (XMLReader) aClass.newInstance();
168 }
169 catch ( ClassNotFoundException e )
170 {
171 return null;
172 }
173 catch ( InstantiationException e )
174 {
175 return null;
176 }
177 catch ( IllegalAccessException e )
178 {
179 return null;
180 }
181 }
182
183
184 private static class DocHandler
185 extends DefaultHandler
186 {
187 private final List<Xpp3Dom> elemStack = new ArrayList<Xpp3Dom>();
188
189 private final List<StringBuilder> values = new ArrayList<StringBuilder>();
190
191
192 private final List<SAXParseException> warnings = new ArrayList<SAXParseException>();
193
194 private final List<SAXParseException> errors = new ArrayList<SAXParseException>();
195
196 private final List<SAXParseException> fatals = new ArrayList<SAXParseException>();
197
198
199 Xpp3Dom result = null;
200
201 private final boolean trim;
202
203 private boolean spacePreserve = false;
204
205 DocHandler( boolean trim )
206 {
207 this.trim = trim;
208 }
209
210 @Override
211 public void startElement( String uri, String localName, String qName, Attributes attributes )
212 throws SAXException
213 {
214 spacePreserve = false;
215 Xpp3Dom child = new Xpp3Dom( localName );
216
217 attachToParent( child );
218 pushOnStack( child );
219
220
221
222 values.add( new StringBuilder() );
223
224 int size = attributes.getLength();
225 for ( int i = 0; i < size; i++ )
226 {
227 String name = attributes.getQName( i );
228 String value = attributes.getValue( i );
229 child.setAttribute( name, value );
230 spacePreserve = spacePreserve || ( "xml:space".equals( name ) && "preserve".equals( value ) );
231 }
232 }
233
234 private boolean pushOnStack( Xpp3Dom child )
235 {
236 return elemStack.add( child );
237 }
238
239 private void attachToParent( Xpp3Dom child )
240 {
241 int depth = elemStack.size();
242 if ( depth > 0 )
243 {
244 elemStack.get( depth - 1 ).addChild( child );
245 }
246 }
247
248 @Override
249 public void warning( SAXParseException e )
250 throws SAXException
251 {
252 warnings.add( e );
253 }
254
255 @Override
256 public void error( SAXParseException e )
257 throws SAXException
258 {
259 errors.add( e );
260 }
261
262 @Override
263 public void fatalError( SAXParseException e )
264 throws SAXException
265 {
266 fatals.add( e );
267 }
268
269 private Xpp3Dom pop()
270 {
271 int depth = elemStack.size() - 1;
272 return elemStack.remove( depth );
273 }
274
275 @Override
276 public void endElement( String uri, String localName, String qName )
277 throws SAXException
278 {
279 int depth = elemStack.size() - 1;
280
281 Xpp3Dom element = pop();
282
283
284 Object accumulatedValue = values.remove( depth );
285
286 if ( element.getChildCount() == 0 )
287 {
288 if ( accumulatedValue == null )
289 {
290 element.setValue( "" );
291 }
292 else
293 {
294 element.setValue( accumulatedValue.toString() );
295 }
296 }
297
298 if ( depth == 0 )
299 {
300 result = element;
301 }
302 }
303
304 @Override
305 public void characters( char[] ch, int start, int length )
306 throws SAXException
307 {
308 String text = new String( ch, start, length );
309 appendToTopValue( ( trim && !spacePreserve ) ? text.trim() : text );
310 }
311
312 private void appendToTopValue( String toAppend )
313 {
314
315 StringBuilder stringBuilder = values.get( values.size() - 1 );
316 stringBuilder.append( toAppend );
317 }
318 }
319
320 }