1 package com.foxinmy.weixin4j.xml;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.OutputStream;
8 import java.io.StringReader;
9 import java.io.StringWriter;
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.concurrent.ConcurrentHashMap;
14
15 import javax.xml.bind.JAXBContext;
16 import javax.xml.bind.JAXBElement;
17 import javax.xml.bind.JAXBException;
18 import javax.xml.bind.Marshaller;
19 import javax.xml.bind.Unmarshaller;
20 import javax.xml.bind.annotation.XmlRootElement;
21 import javax.xml.namespace.QName;
22 import javax.xml.parsers.SAXParserFactory;
23 import javax.xml.stream.XMLInputFactory;
24 import javax.xml.stream.XMLOutputFactory;
25 import javax.xml.stream.XMLStreamConstants;
26 import javax.xml.stream.XMLStreamException;
27 import javax.xml.stream.XMLStreamReader;
28 import javax.xml.stream.XMLStreamWriter;
29 import javax.xml.transform.Source;
30 import javax.xml.transform.sax.SAXSource;
31
32 import org.xml.sax.InputSource;
33 import org.xml.sax.XMLReader;
34
35 import com.alibaba.fastjson.JSONObject;
36 import com.foxinmy.weixin4j.util.Consts;
37 import com.foxinmy.weixin4j.util.StringUtil;
38
39
40
41
42
43
44
45
46
47
48 public final class XmlStream {
49 private final static String ROOT_ELEMENT_XML = "xml";
50 private final static String XML_VERSION = "1.0";
51 private final static ConcurrentHashMap<Class<?>, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class<?>, JAXBContext>();
52 private final static SAXParserFactory spf = SAXParserFactory.newInstance();
53 static {
54 try {
55
56
57
58
59 spf.setFeature(
60 "http://apache.org/xml/features/disallow-doctype-decl",
61 true);
62
63
64
65
66
67
68
69 spf.setFeature(
70 "http://xml.org/sax/features/external-general-entities",
71 false);
72
73
74
75
76
77 spf.setFeature(
78 "http://xml.org/sax/features/external-parameter-entities",
79 false);
80
81 spf.setFeature(
82 "http://apache.org/xml/features/nonvalidating/load-external-dtd",
83 false);
84
85
86 spf.setXIncludeAware(false);
87 } catch (Exception e) {
88 ;
89 }
90 }
91
92
93
94
95
96
97
98
99
100
101 @SuppressWarnings("unchecked")
102 public static <T> T fromXML(InputStream content, Class<T> clazz) {
103 JAXBContext jaxbContext = getJaxbContext(clazz);
104 try {
105 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
106 XMLReader reader = spf.newSAXParser().getXMLReader();
107 reader.setFeature(
108 "http://apache.org/xml/features/disallow-doctype-decl",
109 true);
110 reader.setFeature(
111 "http://apache.org/xml/features/nonvalidating/load-external-dtd",
112 false);
113
114 reader.setFeature(
115 "http://xml.org/sax/features/external-general-entities",
116 false);
117 reader.setFeature(
118 "http://xml.org/sax/features/external-parameter-entities",
119 false);
120 Source source = new SAXSource(reader, new InputSource(content));
121 XmlRootElement rootElement = clazz
122 .getAnnotation(XmlRootElement.class);
123 if (rootElement == null
124 || rootElement.name().equals(
125 XmlRootElement.class.getMethod("name")
126 .getDefaultValue().toString())) {
127 JAXBElement<T> jaxbElement = unmarshaller.unmarshal(source,
128 clazz);
129 return jaxbElement.getValue();
130 } else {
131 return (T) unmarshaller.unmarshal(source);
132 }
133 } catch (Exception ex) {
134 throw new RuntimeException("Could not unmarshaller class [" + clazz
135 + "]", ex);
136 } finally {
137 if (content != null) {
138 try {
139 content.close();
140 } catch (IOException e) {
141 ;
142 }
143 }
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156 public static <T> T fromXML(String content, Class<T> clazz) {
157 return fromXML(
158 new ByteArrayInputStream(content.getBytes(Consts.UTF_8)), clazz);
159 }
160
161
162
163
164
165
166
167
168 public static String map2xml(Map<String, String> map) {
169 StringWriter sw = new StringWriter();
170 try {
171 XMLStreamWriter xw = XMLOutputFactory.newInstance()
172 .createXMLStreamWriter(sw);
173 xw.writeStartDocument(Consts.UTF_8.name(), XML_VERSION);
174 xw.writeStartElement(ROOT_ELEMENT_XML);
175 for (Entry<String, String> entry : map.entrySet()) {
176 if (StringUtil.isBlank(entry.getValue())) {
177 continue;
178 }
179 xw.writeStartElement(entry.getKey());
180 xw.writeCData(entry.getValue());
181 xw.writeEndElement();
182 }
183 xw.writeEndDocument();
184 xw.flush();
185 xw.close();
186 } catch (XMLStreamException e) {
187 throw new IllegalArgumentException(e);
188 } finally {
189 try {
190 sw.close();
191 } catch (IOException e) {
192 ;
193 }
194 }
195 return sw.getBuffer().toString();
196 }
197
198
199
200
201
202
203
204
205 public static String map2xml(JSONObject json) {
206 StringWriter sw = new StringWriter();
207 try {
208 XMLStreamWriter xw = XMLOutputFactory.newInstance()
209 .createXMLStreamWriter(sw);
210 xw.writeStartDocument(Consts.UTF_8.name(), XML_VERSION);
211 xw.writeStartElement(ROOT_ELEMENT_XML);
212 for (Entry<String, Object> entry : json.entrySet()) {
213 if (StringUtil.isBlank(json.getString(entry.getKey()))) {
214 continue;
215 }
216 xw.writeStartElement(entry.getKey());
217 xw.writeCData(json.getString(entry.getKey()));
218 xw.writeEndElement();
219 }
220 xw.writeEndDocument();
221 xw.flush();
222 xw.close();
223 } catch (XMLStreamException e) {
224 throw new IllegalArgumentException(e);
225 } finally {
226 try {
227 sw.close();
228 } catch (IOException e) {
229 ;
230 }
231 }
232 return sw.getBuffer().toString();
233 }
234
235
236
237
238
239
240
241
242 public static Map<String, String> xml2map(String content) {
243 Map<String, String> map = new HashMap<String, String>();
244 StringReader sr = new StringReader(content);
245 try {
246 XMLStreamReader xr = XMLInputFactory.newInstance()
247 .createXMLStreamReader(sr);
248 while (true) {
249 int event = xr.next();
250 if (event == XMLStreamConstants.END_DOCUMENT) {
251 xr.close();
252 break;
253 } else if (event == XMLStreamConstants.START_ELEMENT) {
254 String name = xr.getLocalName();
255 while (true) {
256 event = xr.next();
257 if (event == XMLStreamConstants.START_ELEMENT) {
258 name = xr.getLocalName();
259 } else if (event == XMLStreamConstants.END_ELEMENT) {
260 break;
261 } else if (event == XMLStreamConstants.CHARACTERS) {
262 String value = xr.getText();
263 map.put(name, value);
264 }
265 }
266 }
267 }
268 } catch (XMLStreamException e) {
269 throw new IllegalArgumentException(e);
270 } finally {
271 sr.close();
272 }
273 return map;
274 }
275
276
277
278
279
280
281
282
283 public static String toXML(Object object) {
284 ByteArrayOutputStream os = new ByteArrayOutputStream();
285 toXML(object, os);
286 return StringUtil.newStringUtf8(os.toByteArray());
287 }
288
289
290
291
292
293
294
295
296
297 @SuppressWarnings("unchecked")
298 public static <T> void toXML(T t, OutputStream os) {
299 Class<T> clazz = (Class<T>) t.getClass();
300 JAXBContext jaxbContext = getJaxbContext(clazz);
301 try {
302 Marshaller marshaller = jaxbContext.createMarshaller();
303 marshaller.setProperty(Marshaller.JAXB_ENCODING,
304 Consts.UTF_8.name());
305 XmlRootElement rootElement = clazz
306 .getAnnotation(XmlRootElement.class);
307 if (rootElement == null
308 || rootElement.name().equals(
309 XmlRootElement.class.getMethod("name")
310 .getDefaultValue().toString())) {
311 marshaller.marshal(new JAXBElement<T>(new QName(
312 ROOT_ELEMENT_XML), clazz, t), os);
313 } else {
314 marshaller.marshal(t, os);
315 }
316 } catch (Exception ex) {
317 throw new RuntimeException("Could not marshal class [" + clazz
318 + "] ", ex);
319 } finally {
320 if (os != null) {
321 try {
322 os.close();
323 } catch (IOException e) {
324 ;
325 }
326 }
327 }
328 }
329
330 private static JAXBContext getJaxbContext(Class<?> clazz) {
331 JAXBContext jaxbContext = jaxbContexts.get(clazz);
332 if (jaxbContext == null) {
333 try {
334 jaxbContext = JAXBContext.newInstance(clazz);
335 jaxbContexts.putIfAbsent(clazz, jaxbContext);
336 } catch (JAXBException ex) {
337 throw new RuntimeException(
338 "Could not instantiate JAXBContext for class [" + clazz
339 + "] ", ex);
340 }
341 }
342 return jaxbContext;
343 }
344 }