001: package net.kildenpedersen.xml;
002:
003: import java.io.IOException;
004: import java.io.InputStream;
005: import java.net.URL;
006: import javax.xml.parsers.DocumentBuilder;
007: import javax.xml.parsers.DocumentBuilderFactory;
008: import javax.xml.parsers.ParserConfigurationException;
009:
010: import org.w3c.dom.Document;
011: import org.w3c.dom.Element;
012: import org.w3c.dom.Node;
013: import org.xml.sax.SAXException;
014: import org.xml.sax.SAXParseException;
015:
016: /*
017: * Created on Mar 20, 2004
018: *
019: */
020:
021: /**
022: * Builds a DOM document. Performs XInclude and schema full validation if Xerces
023: * parser is present.
024: *
025: * @author Nils Kilden-Pedersen
026: */
027: public class DOMBuilder {
028:
029: private class StrictErrorHandler implements
030: org.xml.sax.ErrorHandler {
031:
032: /**
033: * @see org.xml.sax.ErrorHandler#error(SAXParseException)
034: */
035: public void error(SAXParseException e) throws SAXException {
036: throw e;
037: }
038:
039: /**
040: * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
041: */
042: public void fatalError(SAXParseException e) throws SAXException {
043: throw e;
044: }
045:
046: /**
047: * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
048: */
049: public void warning(SAXParseException e) throws SAXException {
050: throw e;
051: }
052: }
053:
054: //private static final String XERCES_CONFIG_CLASS_KEY = "org.apache.xerces.xni.parser.XMLParserConfiguration";
055:
056: private static final String XERCES_DOM_IMPL = "org.apache.xerces.dom.DOMImplementationImpl";
057:
058: /*
059: private static final String XERCES_XINCLUDE_CONFIG_CLASS;
060: static {
061: byte[] xercesVersion = getXercesVersion();
062: if (xercesVersion != null && xercesVersion[0] >= 2 && xercesVersion[1] >= 6) {
063: XERCES_XINCLUDE_CONFIG_CLASS =
064: "org.apache.xerces.parsers.XIncludeParserConfiguration";
065: } else {
066: XERCES_XINCLUDE_CONFIG_CLASS = null;
067: }
068: }
069: */
070: private static String getDOMImplementation(
071: DocumentBuilderFactory factory) {
072: try {
073: return factory.newDocumentBuilder().getDOMImplementation()
074: .getClass().getName();
075: } catch (ParserConfigurationException e) {
076: return "";
077: }
078: }
079:
080: /*
081: private static byte[] getXercesVersion() {
082: String versionString;
083: try {
084: versionString = (String)
085: Class.forName("org.apache.xerces.impl.Version").
086: getMethod("getVersion", null).
087: invoke(null, null);
088: } catch (Exception e) {
089: return null;
090: }
091: int spacePos = versionString.indexOf(' ');
092: if (spacePos < 0) {
093: return null;
094: }
095: versionString = versionString.substring(spacePos);
096: byte[] version = new byte[3];
097: StringTokenizer tokens = new StringTokenizer(versionString, " .");
098: byte pos = 0;
099: while (tokens.hasMoreTokens()) {
100: String token = tokens.nextToken();
101: try {
102: version[pos++] = Byte.parseByte(token);
103: } catch (NumberFormatException e) {
104: return null;
105: }
106: }
107: return version;
108:
109: }
110: */
111:
112: /**
113: * Return the first Element
114: *
115: * @param node
116: * @return The first child element or null if no children exist.
117: */
118: public static Element getFirstChildElement(Node node) {
119: Node childNode = node.getFirstChild();
120: do {
121: if (childNode.getNodeType() == Node.ELEMENT_NODE) {
122: return (Element) childNode;
123: }
124: } while ((childNode = childNode.getNextSibling()) != null);
125: return null;
126: }
127:
128: private DocumentBuilder builder = null;
129:
130: /**
131: * Constructor.
132: *
133: */
134: public DOMBuilder() {
135: this (null);
136: }
137:
138: /**
139: * Constructor.
140: *
141: * @param schemaURL
142: */
143: public DOMBuilder(URL schemaURL) {
144: DocumentBuilderFactory factory = DocumentBuilderFactory
145: .newInstance();
146: factory.setNamespaceAware(true);
147: String domImpl = getDOMImplementation(factory);
148: if (schemaURL != null && XERCES_DOM_IMPL.equals(domImpl)) {
149: factory
150: .setAttribute(
151: "http://apache.org/xml/features/validation/dynamic",
152: Boolean.TRUE);
153: factory.setAttribute(
154: "http://apache.org/xml/features/validation/schema",
155: Boolean.TRUE);
156: factory
157: .setAttribute(
158: "http://apache.org/xml/features/validation/schema-full-checking",
159: Boolean.TRUE);
160: factory
161: .setAttribute(
162: "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
163: schemaURL.toExternalForm());
164: }
165:
166: /*
167: // Save any existing config definition
168: String savedConfigClass = System.getProperty(XERCES_CONFIG_CLASS_KEY);
169: if (XERCES_XINCLUDE_CONFIG_CLASS != null) {
170: System.setProperty(XERCES_CONFIG_CLASS_KEY,
171: XERCES_XINCLUDE_CONFIG_CLASS);
172: }
173: */
174:
175: try {
176: this .builder = factory.newDocumentBuilder();
177: } catch (ParserConfigurationException e) {
178: throw new RuntimeException(e);
179: }
180: /*
181: // Reinstate previous config definition, if it existed, otherwise clear
182: if (savedConfigClass != null) {
183: System.setProperty(XERCES_CONFIG_CLASS_KEY, savedConfigClass);
184: } else if(XERCES_XINCLUDE_CONFIG_CLASS != null) {
185: System.getProperties().remove(XERCES_CONFIG_CLASS_KEY);
186: }
187: */
188: this .builder.setErrorHandler(new StrictErrorHandler());
189: }
190:
191: /**
192: * Parse input stream.
193: *
194: * @param xmlDocument
195: * @return DOM document
196: */
197: public Document parse(InputStream xmlDocument) {
198: if (xmlDocument == null) {
199: throw new IllegalArgumentException("XML document is null.");
200: }
201: try {
202: return this .builder.parse(xmlDocument);
203: } catch (SAXException e) {
204: throw new RuntimeException(e);
205: } catch (IOException e) {
206: throw new RuntimeException(e);
207: } finally {
208: try {
209: xmlDocument.close();
210: } catch (IOException e) {
211: throw new RuntimeException(e);
212: }
213:
214: }
215:
216: }
217: }
|