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 import java.io.*;
31 import java.util.ArrayList;
32 import java.util.List;
33
34
35
36
37 public class Xpp3DomBuilder
38 {
39 private static final boolean DEFAULT_TRIM = true;
40
41 public static Xpp3Dom build( @WillClose @Nonnull Reader reader )
42 throws XmlPullParserException
43 {
44 return build( reader, DEFAULT_TRIM );
45 }
46
47 public static Xpp3Dom build( @WillClose InputStream is, @Nonnull String encoding )
48 throws XmlPullParserException
49 {
50 return build( is, encoding, DEFAULT_TRIM );
51 }
52
53 public static Xpp3Dom build( @WillClose InputStream is, @Nonnull String encoding, boolean trim )
54 throws XmlPullParserException
55 {
56 try {
57 Reader reader = new InputStreamReader(is, encoding);
58 return build( reader, trim);
59 } catch (UnsupportedEncodingException e) {
60 throw new RuntimeException(e);
61 }
62 }
63
64 public static Xpp3Dom build( @WillClose Reader reader, boolean trim )
65 throws XmlPullParserException
66 {
67 try
68 {
69 DocHandler docHandler = parseSax(new InputSource(reader), trim);
70 return docHandler.result;
71 }
72 finally
73 {
74 IOUtil.close( reader );
75 }
76 }
77
78 private static DocHandler parseSax(@Nonnull InputSource inputSource, boolean trim) throws XmlPullParserException {
79
80 try {
81 DocHandler ch = new DocHandler(trim);
82 XMLReader parser = org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
83 parser.setContentHandler( ch);
84 parser.parse(inputSource);
85 return ch;
86 } catch (IOException e){
87 throw new XmlPullParserException(e);
88 } catch (SAXException e) {
89 throw new XmlPullParserException(e);
90 }
91 }
92
93
94 private static class DocHandler extends DefaultHandler {
95 private final List<Xpp3Dom> elemStack = new ArrayList<Xpp3Dom>();
96 private final List<StringBuilder> values = new ArrayList<StringBuilder>();
97
98
99 private final List<SAXParseException> warnings = new ArrayList<SAXParseException>();
100 private final List<SAXParseException> errors = new ArrayList<SAXParseException>();
101 private final List<SAXParseException> fatals = new ArrayList<SAXParseException>();
102
103
104 Xpp3Dom result = null;
105
106 private final boolean trim;
107
108 DocHandler(boolean trim) {
109 this.trim = trim;
110 }
111
112 @Override
113 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
114
115 Xpp3Dom child = new Xpp3Dom( localName );
116
117 attachToParent(child);
118 pushOnStack(child);
119
120
121
122 values.add( new StringBuilder() );
123
124 int size = attributes.getLength();
125 for ( int i = 0; i < size; i++ )
126 {
127 child.setAttribute(attributes.getQName(i), attributes.getValue(i));
128 }
129 }
130
131 private boolean pushOnStack(Xpp3Dom child) {
132 return elemStack.add(child);
133 }
134
135 private void attachToParent(Xpp3Dom child) {
136 int depth = elemStack.size();
137 if ( depth > 0 )
138 {
139 elemStack.get(depth - 1).addChild(child);
140 }
141 }
142
143 @Override
144 public void warning(SAXParseException e) throws SAXException {
145 warnings.add(e);
146 }
147
148 @Override
149 public void error(SAXParseException e) throws SAXException {
150 errors.add(e);
151 }
152
153 @Override
154 public void fatalError(SAXParseException e) throws SAXException {
155 fatals.add(e);
156 }
157
158
159 private Xpp3Dom pop()
160 {
161 int depth = elemStack.size() - 1;
162 return elemStack.remove( depth );
163 }
164
165 @Override
166 public void endElement(String uri, String localName, String qName) throws SAXException {
167 int depth = elemStack.size() - 1;
168
169 Xpp3Dom finishedConfiguration = pop();
170
171
172 Object accumulatedValue = values.remove( depth );
173
174 if ( finishedConfiguration.getChildCount() == 0 )
175 {
176 if ( accumulatedValue == null )
177 {
178 finishedConfiguration.setValue( "" );
179 }
180 else
181 {
182 finishedConfiguration.setValue( accumulatedValue.toString() );
183 }
184 }
185
186 if ( depth == 0 )
187 {
188 result = finishedConfiguration;
189 }
190 }
191
192 @Override
193 public void characters(char[] ch, int start, int length) throws SAXException {
194 String text = new String(ch, start, length);
195 appendToTopValue(trim ? text.trim() : text);
196 }
197
198 private void appendToTopValue(String toAppend) {
199
200 StringBuilder stringBuilder = values.get(values.size() - 1);
201 stringBuilder.append( toAppend);
202 }
203 }
204
205 }