1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.kuali.rice.kew.util;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.Reader;
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.lang.reflect.Method;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Vector;
29
30 import javax.xml.XMLConstants;
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34 import javax.xml.transform.OutputKeys;
35 import javax.xml.transform.Result;
36 import javax.xml.transform.Source;
37 import javax.xml.transform.Transformer;
38 import javax.xml.transform.TransformerException;
39 import javax.xml.transform.TransformerFactory;
40 import javax.xml.transform.dom.DOMResult;
41 import javax.xml.transform.dom.DOMSource;
42 import javax.xml.transform.stream.StreamResult;
43 import javax.xml.transform.stream.StreamSource;
44 import javax.xml.xpath.XPath;
45 import javax.xml.xpath.XPathConstants;
46 import javax.xml.xpath.XPathExpressionException;
47
48 import org.apache.commons.lang.StringUtils;
49 import org.jdom.Attribute;
50 import org.jdom.Document;
51 import org.jdom.Element;
52 import org.jdom.JDOMException;
53 import org.jdom.Namespace;
54 import org.jdom.input.DOMBuilder;
55 import org.jdom.input.SAXBuilder;
56 import org.jdom.output.Format;
57 import org.jdom.output.XMLOutputter;
58 import org.kuali.rice.kew.exception.InvalidXmlException;
59 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
60 import org.kuali.rice.kew.util.KEWConstants;
61 import org.kuali.rice.kew.xml.ClassLoaderEntityResolver;
62 import org.kuali.rice.kew.xml.XmlConstants;
63 import org.w3c.dom.NamedNodeMap;
64 import org.w3c.dom.Node;
65 import org.w3c.dom.NodeList;
66 import org.xml.sax.EntityResolver;
67 import org.xml.sax.ErrorHandler;
68 import org.xml.sax.InputSource;
69 import org.xml.sax.SAXException;
70 import org.xml.sax.SAXParseException;
71
72
73
74
75
76
77
78 public class XmlHelper {
79 protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(XmlHelper.class);
80
81 private static final EntityResolver ENTITY_RESOLVER = new ClassLoaderEntityResolver();
82
83 public XmlHelper() {
84 }
85
86 public static org.jdom.Document buildJDocument(StringReader xmlStream) throws InvalidXmlException {
87
88
89 SAXBuilder builder = new SAXBuilder(false);
90 org.jdom.Document doc = null;
91 try {
92 doc = builder.build(xmlStream);
93 }
94
95
96
97 catch (Exception e) {
98 LOG.error("error building jdom document");
99 throw new InvalidXmlException("Invalid xml string. " + e.getMessage());
100 }
101
102 return doc;
103 }
104
105 public static Element getAttributeRootElement(Document document) throws InvalidXmlException {
106 return findElement(document.getRootElement(), KEWConstants.ATTRIBUTE_CONTENT_ELEMENT);
107 }
108
109 public static Element getAttributeElement(Document document, String elementName) throws InvalidXmlException {
110 return findElement(getAttributeRootElement(document), elementName);
111 }
112
113 public static org.jdom.Document buildJDocument(org.w3c.dom.Document document) {
114 return new DOMBuilder().build(document);
115 }
116
117
118
119
120
121
122
123
124
125
126
127 public static org.jdom.Document buildJDocument(StringReader xmlStream, boolean validateXML) throws InvalidXmlException {
128 SAXBuilder builder = new SAXBuilder(false);
129 org.jdom.Document doc = null;
130
131 try {
132 doc = builder.build(xmlStream);
133 }
134
135
136
137 catch (Exception e) {
138 LOG.error("error building jdom document");
139 throw new InvalidXmlException("Invalid xml string. " + e.getMessage());
140 }
141
142 return doc;
143 }
144
145 public static org.w3c.dom.Document buildDocument(String xml) throws IOException, SAXException, ParserConfigurationException {
146 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
147 dbf.setCoalescing(true);
148 DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
149 return documentBuilder.parse(new InputSource(new BufferedReader(new StringReader(xml))));
150 }
151
152
153
154
155
156
157
158
159 public static String readerToString(Reader is) throws IOException {
160
161 StringBuffer sb = new StringBuffer();
162 char[] b = new char[2000];
163 int n;
164
165
166 while ((n = is.read(b)) > 0) {
167 sb.append(b, 0, n);
168 }
169
170
171 return sb.toString();
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185 public static Vector findElements(Element root, String elementName) {
186 Vector elementList = new Vector();
187
188 if (root == null) {
189 return elementList;
190 }
191
192 XmlHelper.findElements(root, elementName, elementList);
193
194 return elementList;
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 public static Element findElement(Element root, String elementName) throws InvalidXmlException {
212 Vector elementList = XmlHelper.findElements(root, elementName);
213
214 if (elementList.size() < 1) {
215 return null;
216 }
217
218 if (elementList.size() > 1) {
219 throw new InvalidXmlException("More than one element in root");
220 }
221
222 return (Element) elementList.get(0);
223 }
224
225
226
227
228
229
230
231
232
233
234 public static Element makeElement(String elementName, String value) throws Exception {
235 if ((elementName == null) || elementName.trim().equals("")) {
236 throw new Exception("Programmatic error: Element Name passed in null or blank");
237 }
238
239 Element element = new Element(elementName);
240
241 if ((value == null) || value.trim().equals("")) {
242 element.setAttribute("value", "");
243 } else {
244 element.setAttribute("value", value);
245 }
246
247 return element;
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261
262 public static String getElementAttributeValue(Element root, String elementName, String attributeName) throws InvalidXmlException {
263 Element element = XmlHelper.findElement(root, elementName);
264 Attribute attribute = element.getAttribute(attributeName);
265
266 if (attribute == null) {
267 throw new InvalidXmlException("The Attribute name given is not present in the element " + element.getName());
268 }
269
270 return attribute.getValue();
271 }
272
273
274
275
276
277
278
279
280
281 private static void findElements(Element root, String elementName, List list) {
282 if (root != null) {
283 if (root.getName().equals(elementName)) {
284 list.add(root);
285 }
286
287 Iterator iter = root.getChildren().iterator();
288
289 while (iter.hasNext()) {
290 Element item = (Element) iter.next();
291
292 if (item != null) {
293 XmlHelper.findElements(item, elementName, list);
294 }
295 }
296 }
297 }
298
299 public static String getTextContent(org.w3c.dom.Element element) {
300 NodeList children = element.getChildNodes();
301 Node node = children.item(0);
302 return node.getNodeValue();
303 }
304
305 public static String jotDocument(org.jdom.Document document) {
306 XMLOutputter outputer = new XMLOutputter(Format.getPrettyFormat());
307 StringWriter writer = new StringWriter();
308 try {
309 outputer.output(document, writer);
310 } catch (IOException e) {
311 throw new WorkflowRuntimeException("Could not write XML data export.", e);
312 }
313 return writer.toString();
314 }
315
316 public static String jotNode(org.jdom.Element element) {
317 XMLOutputter outputer = new XMLOutputter(Format.getPrettyFormat());
318 StringWriter writer = new StringWriter();
319 try {
320 outputer.output(element, writer);
321 } catch (IOException e) {
322 throw new WorkflowRuntimeException("Could not write XML data export.", e);
323 }
324 return writer.toString();
325 }
326
327 public static String jotNode(org.w3c.dom.Node node) {
328
329 return jotNode(node, true);
330 }
331
332 public static String jotNode(org.w3c.dom.Node node, boolean indent) {
333 try {
334 return writeNode(node, indent);
335 } catch (TransformerException te) {
336 return Utilities.collectStackTrace(te);
337 }
338 }
339
340 public static String writeNode(org.w3c.dom.Node node) throws TransformerException {
341 return writeNode(node, false);
342 }
343
344 public static String writeNode(org.w3c.dom.Node node, boolean indent) throws TransformerException {
345 Source source = new DOMSource(node);
346 StringWriter writer = new StringWriter();
347 Result result = new StreamResult(writer);
348 Transformer transformer = TransformerFactory.newInstance().newTransformer();
349 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
350 if (indent) {
351 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
352 }
353 transformer.transform(source, result);
354 return writer.toString();
355 }
356
357 public static void appendXml(Node parentNode, String xml) throws SAXException, IOException, ParserConfigurationException {
358 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
359 factory.setValidating(false);
360 org.w3c.dom.Document xmlDocument = factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
361 org.w3c.dom.Element xmlDocumentElement = xmlDocument.getDocumentElement();
362 Node importedNode = parentNode.getOwnerDocument().importNode(xmlDocumentElement, true);
363 parentNode.appendChild(importedNode);
364 }
365
366 public static org.w3c.dom.Document readXml(String xml) throws TransformerException {
367 Source source = new StreamSource(new BufferedReader(new StringReader(xml)));
368 DOMResult result = new DOMResult();
369 Transformer transformer = TransformerFactory.newInstance().newTransformer();
370 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
371 transformer.transform(source, result);
372 return (org.w3c.dom.Document) result.getNode();
373 }
374
375 public static void propogateNamespace(Element element, Namespace namespace) {
376 element.setNamespace(namespace);
377 for (Iterator iterator = element.getChildren().iterator(); iterator.hasNext();) {
378 Element childElement = (Element) iterator.next();
379 propogateNamespace(childElement, namespace);
380 }
381 }
382
383 public static org.w3c.dom.Document trimXml(InputStream input) throws SAXException, IOException, ParserConfigurationException {
384 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
385 factory.setIgnoringElementContentWhitespace(true);
386 DocumentBuilder builder = factory.newDocumentBuilder();
387 org.w3c.dom.Document oldDocument = builder.parse(input);
388 org.w3c.dom.Element naviElement = oldDocument.getDocumentElement();
389 trimElement(naviElement);
390 return oldDocument;
391 }
392
393 public static void trimElement(Node node) throws SAXException, IOException, ParserConfigurationException {
394
395 if (node.hasChildNodes()) {
396
397
398 NodeList children = node.getChildNodes();
399 for (int i = 0; i < children.getLength(); i++) {
400 Node child = children.item(i);
401 if (child != null) {
402
403
404 trimElement(child);
405 }
406 }
407 } else {
408
409
410 if (node.getNodeType() == Node.TEXT_NODE) {
411 String text = node.getNodeValue();
412 if (Utilities.isEmpty(text)) {
413 text = "";
414 } else {
415 text = text.trim();
416 }
417 node.setNodeValue(text);
418 }
419 }
420 }
421
422 public static void printDocumentStructure(org.w3c.dom.Document doc) {
423 org.w3c.dom.Element naviElement = doc.getDocumentElement();
424 printNode(naviElement, 0);
425 }
426
427 public static void printNode(Node node, int level) {
428 if (node.getNodeType() == Node.TEXT_NODE) {
429 if (LOG.isInfoEnabled()) {
430 LOG.info(node.getNodeValue());
431 }
432 return;
433 } else {
434 final StringBuilder log = new StringBuilder();
435
436
437
438
439 log.append("<" + node.getNodeName());
440 if (node.hasAttributes()) {
441 NamedNodeMap attrMap = node.getAttributes();
442 for (int i = 0; i < attrMap.getLength(); i++) {
443 org.w3c.dom.Attr attribute = (org.w3c.dom.Attr) attrMap.item(i);
444 log.append(" " + attribute.getName().trim() + "=\"" + attribute.getValue() + "\"");
445 }
446 }
447 log.append(">");
448 if (node.hasChildNodes()) {
449 NodeList children = node.getChildNodes();
450 for (int i = 0; i < children.getLength(); i++) {
451 Node child = children.item(i);
452 if (child != null) {
453
454
455 printNode(child, level + 1);
456 }
457 }
458 }
459 log.append("</" + node.getNodeName() + ">");
460 if (LOG.isInfoEnabled()) {
461 LOG.info(log);
462 }
463 }
464 }
465
466 public static Document trimSAXXml(InputStream input) throws JDOMException, SAXException, IOException, ParserConfigurationException {
467 SAXBuilder builder = new SAXBuilder(false);
468 Document oldDocument = builder.build(input);
469 Element naviElement = oldDocument.getRootElement();
470 trimSAXElement(naviElement);
471 return oldDocument;
472 }
473
474 public static void trimSAXElement(Element element) throws SAXException, IOException, ParserConfigurationException {
475
476 if (! element.getChildren().isEmpty()) {
477
478 java.util.List children = element.getChildren();
479 for (int i = 0; i < children.size(); i++) {
480 Element child = (Element) children.get(i);
481 if (child != null) {
482
483
484 trimSAXElement(child);
485 }
486 }
487 } else {
488
489
490
491 String text = element.getTextTrim();
492 if (Utilities.isEmpty(text)) {
493 text = "";
494 }
495 element.setText(text);
496
497 }
498 }
499
500 public static void printSAXDocumentStructure(Document doc) {
501 Element naviElement = doc.getRootElement();
502 printSAXNode(naviElement, 0);
503 }
504
505 public static void printSAXNode(Element element, int level) {
506 if (element.getChildren().isEmpty()) {
507 if (LOG.isInfoEnabled()) {
508 LOG.info("<" + element.getName().trim() + ">" + element.getText() + "</" + element.getName().trim() + ">");
509 }
510 return;
511 } else {
512 final StringBuilder log = new StringBuilder();
513
514
515
516
517 log.append("<" + element.getName());
518 org.jdom.Namespace ns = element.getNamespace();
519 if (ns != null) {
520 log.append(" xmlns=\"" + ns.getURI() + "\"");
521
522 }
523 ns = element.getNamespace("xsi");
524 if (ns != null) {
525 log.append(" xmlns:" + ns.getPrefix() + "=\"" + ns.getURI() + "\"");
526 }
527 if (element.getAttributes() != null && element.getAttributes().size() > 0) {
528 List attrMap = element.getAttributes();
529 for (int i = 0; i < attrMap.size(); i++) {
530 Attribute attribute = (Attribute) attrMap.get(i);
531 ns = attribute.getNamespace();
532 log.append(" ");
533 if (ns != null) {
534 log.append(ns.getPrefix() + ":");
535 }
536 log.append(attribute.getName().trim() + "=\"" + attribute.getValue() + "\"");
537 }
538 }
539 log.append(">");
540 List children = element.getChildren();
541 for (int i = 0; i < children.size(); i++) {
542 Element child = (Element) children.get(i);
543 if (child != null) {
544
545
546 printSAXNode(child, level + 1);
547 }
548 }
549
550 log.append("</" + element.getName() + ">");
551 if (LOG.isInfoEnabled()) {
552 LOG.info(log);
553 }
554 }
555 }
556
557
558
559
560
561
562
563
564
565
566
567
568
569 public static boolean pathExists(XPath xpath, String expression, Object object) throws XPathExpressionException {
570 return ((Boolean) xpath.evaluate(expression, object, XPathConstants.BOOLEAN)).booleanValue();
571 }
572
573 public static void validate(final InputSource source) throws ParserConfigurationException, IOException, SAXException {
574 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
575 dbf.setValidating(true);
576 dbf.setNamespaceAware( true );
577 dbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", XMLConstants.W3C_XML_SCHEMA_NS_URI);
578 DocumentBuilder db = dbf.newDocumentBuilder();
579 db.setEntityResolver(ENTITY_RESOLVER);
580 db.setErrorHandler(new ErrorHandler() {
581 public void warning(SAXParseException se) {
582 LOG.warn("Warning parsing xml doc " + source, se);
583 }
584 public void error(SAXParseException se) throws SAXException {
585 LOG.error("Error parsing xml doc " + source, se);
586 throw se;
587 }
588 public void fatalError(SAXParseException se) throws SAXException {
589 LOG.error("Fatal error parsing xml doc " + source, se);
590 throw se;
591 }
592 });
593 db.parse(source);
594 }
595
596 public static org.w3c.dom.Element propertiesToXml(org.w3c.dom.Document doc, Object o, String elementName) throws Exception {
597 Class c = o.getClass();
598 org.w3c.dom.Element wrapper = doc.createElement(elementName);
599 Method[] methods = c.getMethods();
600 for (Method method : methods) {
601 String name = method.getName();
602 if ("getClass".equals(name)) continue;
603 if (!name.startsWith("get") ||
604 method.getParameterTypes().length > 0) continue;
605 name = name.substring("get".length());
606 name = StringUtils.uncapitalize(name);
607 String value = null;
608 try {
609 Object result = method.invoke(o, null);
610 if (result == null) {
611 LOG.debug("value of " + name + " method on object " + o.getClass() + " is null");
612 value = "";
613 } else {
614 value = result.toString();
615 }
616 org.w3c.dom.Element fieldE = doc.createElement(name);
617 fieldE.appendChild(doc.createTextNode(value));
618 wrapper.appendChild(fieldE);
619 } catch (RuntimeException e) {
620 LOG.error("Error accessing method '" + method.getName() + "' of instance of " + c);
621 throw e;
622 } catch (Exception e) {
623 LOG.error("Error accessing method '" + method.getName() + "' of instance of " + c);
624 }
625 }
626 return wrapper;
627 }
628
629 public static String getChildElementText(org.w3c.dom.Element parent, String childElementName) {
630 NodeList childNodes = parent.getChildNodes();
631 for (int index = 0; index < childNodes.getLength(); index++) {
632 org.w3c.dom.Node node = childNodes.item(index);
633 if (Node.ELEMENT_NODE == node.getNodeType()) {
634 org.w3c.dom.Element element = (org.w3c.dom.Element)node;
635 if (XmlConstants.DOCUMENT_TYPE.equals(element.getNodeName())) {
636 return element.getTextContent();
637 }
638 }
639 }
640 return null;
641 }
642 }