001: /*
002: * Project: Gulden Utilies
003: * Class: de.gulden.util.xml.XMLToolbox
004: * Version: snapshot-beautyj-1.1
005: *
006: * Date: 2004-09-29
007: *
008: * This is a snapshot version of the Gulden Utilities,
009: * it is not released as a seperate version.
010: *
011: * Note: Contains auto-generated Javadoc comments created by BeautyJ.
012: *
013: * This is licensed under the GNU Lesser General Public License (LGPL)
014: * and comes with NO WARRANTY.
015: *
016: * Author: Jens Gulden
017: * Email: amoda@jensgulden.de
018: */
019:
020: package de.gulden.util.xml;
021:
022: import de.gulden.util.Toolbox;
023: import de.gulden.util.xml.NodeListImpl;
024: import java.io.*;
025: import java.util.*;
026: import java.util.Collection;
027: import javax.xml.parsers.*;
028: import org.w3c.dom.*;
029:
030: /**
031: * Class XMLToolbox.
032: *
033: * @author Jens Gulden
034: * @version snapshot-beautyj-1.1
035: */
036: public class XMLToolbox {
037:
038: // ------------------------------------------------------------------------
039: // --- static field ---
040: // ------------------------------------------------------------------------
041:
042: /**
043: * The parse x m l document builder.
044: */
045: protected static DocumentBuilder parseXMLDocumentBuilder;
046:
047: // ------------------------------------------------------------------------
048: // --- static methods ---
049: // ------------------------------------------------------------------------
050:
051: /**
052: * Creates the default document builder.
053: */
054: public static DocumentBuilder createDefaultDocumentBuilder() {
055: try {
056: javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory
057: .newInstance();
058: return factory.newDocumentBuilder();
059: } catch (Exception e) {
060: System.err
061: .println("fatal error: cannot create default DocumentBuilder");
062: System.err.println(e.getClass().getName() + " - "
063: + e.getMessage());
064: e.printStackTrace(System.err);
065: System.exit(2);
066: return null;
067: }
068: }
069:
070: /**
071: * Creates the default document builder.
072: */
073: public static DocumentBuilder createDefaultDocumentBuilder(
074: boolean validating, boolean namespaceAware,
075: boolean ignoringElementContentWhitespace,
076: boolean ignoringComments, boolean expandEntityReferences,
077: boolean coalescing) {
078: try {
079: javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory
080: .newInstance();
081: factory.setValidating(validating);
082: factory.setNamespaceAware(namespaceAware);
083: factory
084: .setIgnoringElementContentWhitespace(ignoringElementContentWhitespace);
085: factory.setIgnoringComments(ignoringComments);
086: factory.setExpandEntityReferences(expandEntityReferences);
087: factory.setCoalescing(coalescing);
088: return factory.newDocumentBuilder();
089: } catch (Exception e) {
090: System.err
091: .println("fatal error: cannot create default DocumentBuilder");
092: System.err.println(e.getClass().getName() + " - "
093: + e.getMessage());
094: e.printStackTrace(System.err);
095: System.exit(2);
096: return null;
097: }
098: }
099:
100: /**
101: * Returns the first child with the specified tagname.
102: */
103: public static Element getChild(Element e, String tagname) {
104: Node n = e.getFirstChild();
105: while (n != null) {
106: if (n instanceof Element) {
107: Element c = (Element) n;
108: if (c.getTagName().equals(tagname)) {
109: return c;
110: }
111: }
112: n = n.getNextSibling();
113: }
114: return null;
115: }
116:
117: /**
118: * Returns the first child with the specified tagname and the named attribute set to the given value.
119: */
120: public static Element getChild(Element e, String tagname,
121: String attributeName, String attributeValue) {
122: Node n = e.getFirstChild();
123: while (n != null) {
124: if (n instanceof Element) {
125: Element c = (Element) n;
126: if (c.getTagName().equals(tagname)) {
127: if (c.hasAttribute(attributeName)
128: && c.getAttribute(attributeName).equals(
129: attributeValue)) {
130: return c;
131: }
132: }
133: }
134: n = n.getNextSibling();
135: }
136: return null;
137: }
138:
139: /**
140: * Returns the child required.
141: */
142: public static Element getChildRequired(Element e, String tagname)
143: throws XMLException {
144: Element c = getChild(e, tagname);
145: if (c == null) {
146: throw new XMLException("child tag '<" + tagname
147: + "'> required", e);
148: }
149: return c;
150: }
151:
152: /**
153: * Returns the attribute required.
154: */
155: public static String getAttributeRequired(Element e, String att)
156: throws XMLException {
157: String a = e.getAttribute(att);
158: if ((a == null) || (a.length() == 0)) {
159: throw new XMLException("attribute '" + att + "' required",
160: e);
161: }
162: return a;
163: }
164:
165: /**
166: * Returns the children.
167: */
168: public static NodeListCollection getChildren(Element e,
169: String tagname) {
170: NodeListImpl nl = new NodeListImpl();
171: Node n = e.getFirstChild();
172: while (n != null) {
173: if (n instanceof Element) {
174: Element c = (Element) n;
175: if (c.getTagName().equals(tagname)) {
176: nl.add(c);
177: }
178: }
179: n = n.getNextSibling();
180: }
181: return nl;
182: }
183:
184: public static boolean isYesAttribute(Element e, String attr) {
185: return getBooleanAttribute(e, attr, false);
186: }
187:
188: /**
189: * Returns the text.
190: */
191: public static String getText(Element e) {
192: Node n = e.getFirstChild();
193: if ((n != null) && (n instanceof CharacterData)) {
194: String t = ((CharacterData) n).getData();
195: return t;
196: } else {
197: return null;
198: }
199: }
200:
201: /**
202: * Returns the child text.
203: */
204: public static String getChildText(Element e, String tagname) {
205: Element child = getChild(e, tagname);
206: if (child != null) {
207: return getText(child);
208: } else {
209: return null;
210: }
211: }
212:
213: public static void requireTagName(Element element, String name)
214: throws XMLException {
215: if (!element.getTagName().equals(name)) {
216: throw new XMLException("illegal XML tag - expected <"
217: + name + ">", element);
218: }
219: }
220:
221: /**
222: * Returns the first child.
223: */
224: public static Element getFirstChild(Element e) {
225: return getSelfOrFollowingElement(e.getFirstChild());
226: }
227:
228: /**
229: * Returns the children.
230: */
231: public static NodeListCollection getChildren(Element e) {
232: NodeListCollection c = new NodeListImpl();
233: Element ee = getFirstChild(e);
234: while (ee != null) {
235: c.add(ee);
236: ee = getFollowingElement(ee);
237: }
238: return c;
239: }
240:
241: /**
242: * Returns the self or following element.
243: */
244: public static Element getSelfOrFollowingElement(Node n) {
245: while ((n != null) && (!(n instanceof Element))) {
246: n = n.getNextSibling();
247: }
248: return (Element) n;
249: }
250:
251: /**
252: * Returns the following element.
253: */
254: public static Element getFollowingElement(Node n) {
255: // DEPRECATED
256: return getNextSibling(n);
257: }
258:
259: /**
260: * Returns the langstring.
261: */
262: public static String getLangstring(Element element,
263: String countryCode) {
264: if (element != null) { // make null-safe to allow easier calling from nested functions
265: org.w3c.dom.NodeList nl = getChildren(element, "langstring");
266: if (nl.getLength() > 0) {
267: org.w3c.dom.Element defaultElement = null;
268: for (int i = 0; i < nl.getLength(); i++) {
269: Element e = (Element) nl.item(i);
270: String c = e.getAttribute("lang");
271: if ((c.equals("")) && (defaultElement == null)) {
272: defaultElement = e;
273: if (countryCode == null) {
274: return getText(e); // default found
275: }
276: } else if ((countryCode != null)
277: && (countryCode.equalsIgnoreCase(c))) { // explicit lang wanted
278: return getText(e); // language found
279: }
280: }
281: // not explicitly found, use default
282: if (defaultElement != null) {
283: // (countryCode!=null) here, otherwise already returned
284: return getText(defaultElement); // return default if there was a <langstring> without explicit lang attribute, although AN EXPLICIT LANGUAGE HAD BEEN REQUESTED HERE
285: } else {
286: // last chance: if no default <langstring> without lang attribute
287: if (countryCode == null) { // but also no lang was explicitly requested
288: return getText((Element) nl.item(0)); // use first entry as default
289: } else {
290: return null; // not found
291: }
292: }
293: } else {
294: return null;
295: }
296: } else {
297: return null;
298: }
299: }
300:
301: /**
302: * Returns the langstring.
303: */
304: public static String getLangstring(Element element) {
305: return getLangstring(element, null); // default language
306: }
307:
308: public static String translateJavaNameToXMLName(String name) {
309: int pos = 0;
310: // skip while uppercase letters
311: while ((pos < name.length())
312: && (Character.isUpperCase(name.charAt(pos)))) {
313: pos++;
314: }
315: // skip to first uppercase letter
316: while ((pos < name.length())
317: && (Character.isLowerCase(name.charAt(pos)))) {
318: pos++;
319: }
320: // build result
321: if (pos > 0) {
322: if (pos < name.length()) {
323: return name.substring(0, pos).toLowerCase()
324: + "-"
325: + translateJavaNameToXMLName(name
326: .substring(pos));
327: } else {
328: return name.toLowerCase();
329: }
330: } else {
331: return "";
332: }
333: }
334:
335: public static String translateXMLNameToJavaName(String name) {
336: // name must not be ""
337: StringTokenizer st = new StringTokenizer(name, "-", false);
338: StringBuffer sb = new StringBuffer(st.nextToken());
339: while (st.hasMoreTokens()) {
340: String t = st.nextToken();
341: sb.append(de.gulden.util.Toolbox.capitalize(t));
342: }
343: return sb.toString();
344: }
345:
346: /**
347: * Returns the next sibling.
348: */
349: public static Element getNextSibling(Node n) {
350: return getSelfOrFollowingElement(n.getNextSibling());
351: }
352:
353: /**
354: * Returns the children.
355: */
356: public static NodeListCollection getChildren(Element e,
357: String[] tagnames) {
358: NodeListImpl nl = new NodeListImpl();
359: Node n = e.getFirstChild();
360: while (n != null) {
361: if (n instanceof Element) {
362: Element c = (Element) n;
363: if (Toolbox.arrayContains(tagnames, c.getTagName())) {
364: nl.add(c);
365: }
366: }
367: n = n.getNextSibling();
368: }
369: return nl;
370: }
371:
372: /**
373: * Parses the x m l.
374: */
375: public static Element parseXML(String s) throws XMLException {
376: try {
377: if (parseXMLDocumentBuilder == null) {
378: parseXMLDocumentBuilder = createDefaultDocumentBuilder();
379: if (parseXMLDocumentBuilder == null) {
380: throw new XMLException(
381: "Internal error: cannot parse XML - could not create document builder");
382: }
383: }
384: java.io.StringBufferInputStream in = new java.io.StringBufferInputStream(
385: s);
386: org.w3c.dom.Document doc = parseXMLDocumentBuilder
387: .parse(in);
388: Element xml = doc.getDocumentElement();
389: return xml;
390: } catch (java.io.IOException ioe) {
391: throw new XMLException("cannot parse XML", ioe);
392: } catch (org.xml.sax.SAXException saxe) {
393: throw new XMLException("cannot parse XML", saxe);
394: }
395: }
396:
397: public static String formatXML(Node xml, boolean indenting,
398: boolean preserveSpace) {
399: // returns null in case of errors
400: // trows Error if xml is not of type Document or Element
401: try {
402: java.io.StringWriter out = new java.io.StringWriter();
403: org.apache.xml.serialize.OutputFormat outputFormat = new org.apache.xml.serialize.OutputFormat();
404: outputFormat.setIndenting(indenting);
405: outputFormat.setPreserveSpace(preserveSpace);
406: org.apache.xml.serialize.XMLSerializer serializer = new org.apache.xml.serialize.XMLSerializer(
407: out, outputFormat);
408: org.apache.xml.serialize.DOMSerializer domSerializer = serializer
409: .asDOMSerializer();
410: if (xml instanceof Element) {
411: domSerializer.serialize((Element) xml);
412: } else if (xml instanceof Document) {
413: domSerializer.serialize((Document) xml);
414: } else {
415: throw new Error(
416: "internal error: can only xml-serialize objects of type Element or Document");
417: }
418: return out.toString();
419: } catch (java.io.IOException ioe) {
420: return null;
421: }
422: }
423:
424: /**
425: * Returns the boolean attribute.
426: */
427: public static boolean getBooleanAttribute(Element e, String attr,
428: boolean deflt) {
429: String a = e.getAttribute(attr);
430: if (Toolbox.empty(a)) {
431: return deflt;
432: } else {
433: a = a.trim().toLowerCase();
434: if (deflt == true) {
435: return !Toolbox.isNo(a);
436: } else {
437: return Toolbox.isYes(a);
438: }
439: }
440: }
441:
442: /**
443: * <p>
444: * Returns an attribute's value.
445: * </p>
446: * <p>
447: */
448: public static String getAttribute(Element e, String name,
449: String deflt) {
450: boolean has = e.hasAttribute(name);
451: if (has) {
452: return e.getAttribute(name);
453: } else {
454: return deflt;
455: }
456: }
457:
458: /**
459: * <p>
460: * Returns an attribute's value. Note that unlike
461: * org.w3c.dom.Element.getAttribute(name), this method returns <b>null</b>
462: * if the attribute does not exist on the element. The empty string is only
463: * returned if the attribute actually contains the empty string as value.
464: * </p>
465: * <p>
466: *
467: * @param e The element which carries an attribute.
468: * </p>
469: * <p>
470: * @param name The name of the attribute.
471: * </p>
472: * <p>
473: * @return a String with the attribtue's value, <b>null</b> if the
474: * attribute is absent on the element.
475: * </p>
476: */
477: public static String getAttribute(Element e, String name) {
478: return getAttribute(e, name, null);
479: }
480:
481: public static String xmlEscape(String s) {
482: // needed optimization:
483: StringBuffer sb = new StringBuffer();
484: int len = s.length();
485: int lastPos = 0;
486: int nextOpen = s.indexOf('<');
487: int nextClose = s.indexOf('>');
488: boolean opens = (nextOpen != -1);
489: boolean closes = (nextClose != -1);
490: do {
491: if ((opens && !closes)
492: || (opens /* && closes */&& (nextOpen < nextClose))) {
493: String part = s.substring(lastPos, nextOpen);
494: sb.append(part);
495: sb.append("<");
496: lastPos = nextOpen + 1;
497: nextOpen = s.indexOf('<', lastPos);
498: opens = (nextOpen != -1);
499: } else if (closes) { // ( closes && ! opens ) || ( closes /* && opens */ && (nextClose<nextOpen) )
500: String part = s.substring(lastPos, nextClose);
501: sb.append(part);
502: sb.append(">");
503: lastPos = nextClose + 1;
504: nextClose = s.indexOf('>', lastPos);
505: closes = (nextClose != -1);
506: }
507: } while (opens || closes);
508: if (lastPos < len) {
509: String rest = s.substring(lastPos);
510: sb.append(rest);
511: }
512: return sb.toString();
513: }
514:
515: public static String xmlEscapeAll(String s) {
516: char[] c = { '<', '>', '\"', '\'', '\n', '\r' };
517: String[] r = { "<", ">", """, "'", "
", "" };
518: return Toolbox.replaceCharsWithStrings(s, c, r);
519: }
520:
521: } // end XMLToolbox
|