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