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