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 XmlPullParserException( 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 values.add( new StringBuilder() );
212
213 int size = attributes.getLength();
214 for ( int i = 0; i < size; i++ )
215 {
216 String name = attributes.getQName( i );
217 String value = attributes.getValue( i );
218 child.setAttribute( name, value );
219 spacePreserve = spacePreserve || ( "xml:space".equals( name ) && "preserve".equals( value ) );
220 }
221 }
222
223 private boolean pushOnStack( Xpp3Dom child )
224 {
225 return elemStack.add( child );
226 }
227
228 private void attachToParent( Xpp3Dom child )
229 {
230 int depth = elemStack.size();
231 if ( depth > 0 )
232 {
233 elemStack.get( depth - 1 ).addChild( child );
234 }
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 }