001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.visualweb.complib;
043:
044: import java.io.File;
045: import java.lang.reflect.Method;
046: import java.net.URI;
047: import java.net.URISyntaxException;
048: import java.net.URL;
049:
050: import javax.xml.parsers.DocumentBuilder;
051: import javax.xml.parsers.DocumentBuilderFactory;
052: import javax.xml.parsers.ParserConfigurationException;
053: import javax.xml.transform.OutputKeys;
054: import javax.xml.transform.Transformer;
055: import javax.xml.transform.TransformerException;
056: import javax.xml.transform.TransformerFactory;
057: import javax.xml.transform.dom.DOMSource;
058: import javax.xml.transform.stream.StreamResult;
059:
060: import org.w3c.dom.Document;
061: import org.w3c.dom.Element;
062: import org.w3c.dom.Node;
063: import org.w3c.dom.NodeList;
064:
065: /**
066: * Utilities to provide a simpler interface to JAXP, the standard Java API for
067: * XML Processing. Currently based on DOM.
068: *
069: * @author Edwin Goei
070: */
071: public class XmlUtil {
072: private static Method xalanMethod;
073:
074: private Document doc;
075:
076: private DocumentBuilder db;
077:
078: public XmlUtil() {
079: this (null);
080: }
081:
082: public XmlUtil(Document doc) {
083: DocumentBuilderFactory dbf = DocumentBuilderFactory
084: .newInstance();
085: dbf.setNamespaceAware(true);
086: try {
087: db = dbf.newDocumentBuilder();
088: } catch (ParserConfigurationException e) {
089: assert false;
090: throw new RuntimeException(e.getMessage(), e);
091: }
092: this .doc = doc;
093: }
094:
095: public Document read(File inFile) throws XmlException {
096: try {
097: doc = db.parse(inFile);
098: } catch (Exception e) {
099: throw new XmlException("Unable to parse input file: "
100: + inFile, e);
101: }
102: return doc;
103: }
104:
105: public Document read(URI uri) throws XmlException {
106: // TODO check how to close the input
107: try {
108: doc = db.parse(uri.toASCIIString());
109: } catch (Exception e) {
110: throw new XmlException("Unable to parse input URI: " + uri,
111: e);
112: }
113: return doc;
114: }
115:
116: public Document read(URL url) throws XmlException {
117: URI uri;
118: try {
119: uri = new URI(url.toExternalForm());
120: } catch (URISyntaxException e) {
121: throw new XmlException("Unable to parse input URL: " + url,
122: e);
123: }
124: read(uri);
125: return doc;
126: }
127:
128: public Document createDocument() {
129: doc = db.newDocument();
130: return doc;
131: }
132:
133: public Document getDocument() {
134: if (doc == null) {
135: createDocument();
136: }
137: return doc;
138: }
139:
140: /**
141: * Use namespace version of createElement to create an element with a
142: * unqualified name
143: *
144: * @param name
145: * @return
146: */
147: public Element createElement(String name) {
148: return getDocument().createElementNS(null, name);
149: }
150:
151: /**
152: * Write document to File using formatting. This will also close the output
153: * file (I think).
154: *
155: * @param outFile
156: * @throws XmlException
157: */
158: public void write(File outFile) throws XmlException {
159: DOMSource domSource = new DOMSource(getDocument());
160: StreamResult streamResult = new StreamResult(outFile);
161: TransformerFactory tf = TransformerFactory.newInstance();
162: try {
163: Transformer xform = tf.newTransformer();
164: // Format using 2 space indent. Output property name may depend
165: // on version of Xalan being used so set both names.
166: xform.setOutputProperty(OutputKeys.INDENT, "yes");
167: xform.setOutputProperty(
168: "{http://xml.apache.org/xslt}indent-amount", "2");
169: xform.setOutputProperty(
170: "{http://xml.apache.org/xalan}indent-amount", "2");
171: xform.transform(domSource, streamResult);
172: } catch (TransformerException e) {
173: throw new XmlException("Unable to write to file: "
174: + outFile, e);
175: }
176: }
177:
178: /**
179: * @param contextNode
180: * Node to start from
181: * @param xpath
182: * XPath expression
183: * @return NodeList containing resulting Nodes
184: * @throws XmlException
185: */
186: public static NodeList selectNodeList(Node contextNode, String xpath)
187: throws XmlException {
188: // TODO maybe we should return an empty NodeList instead of null
189: if (xalanMethod == null) {
190: // FIXME This is a hack to get an XPath API working. We should use
191: // the javax XPath API instead in Java 5, but we need to compile on
192: // JDK 1.4 and run on JDK 5.
193: Class clazz;
194: try {
195: clazz = Class.forName(
196: "com.sun.org.apache.xpath.internal.XPathAPI",
197: true, // NOI18N
198: Thread.currentThread().getContextClassLoader());
199: } catch (ClassNotFoundException e) {
200: IdeUtil
201: .logWarning(
202: "JDK 5 version failed, so will next try JDK 1.4",
203: e); // NOI18N
204: try {
205: clazz = Class.forName("org.apache.xpath.XPathAPI",
206: true, // NOI18N
207: Thread.currentThread()
208: .getContextClassLoader());
209: } catch (ClassNotFoundException e1) {
210: IdeUtil.logWarning(e1);
211: return null;
212: }
213: }
214:
215: try {
216: xalanMethod = clazz.getDeclaredMethod("selectNodeList", // NOI18N
217: new Class[] { Node.class, String.class });
218: } catch (Exception e) {
219: IdeUtil.logWarning(e);
220: return null;
221: }
222: }
223:
224: Object result = null;
225: try {
226: result = xalanMethod.invoke(null, new Object[] {
227: contextNode, xpath });
228: } catch (Exception e) {
229: IdeUtil.logWarning(e);
230: }
231: return (NodeList) result;
232:
233: // The following doesn't work with the NB Module ClassLoader
234: // try {
235: // return XPathAPI.selectNodeList(contextNode, xpath);
236: // } catch (TransformerException e) {
237: // throw new XmlException("selectNodeList", e);
238: // }
239: }
240:
241: /**
242: * @param contextNode
243: * Node to start from
244: * @param xpath
245: * XPath expression
246: * @return The first node found that matches the XPath, or null.
247: * @throws XmlException
248: */
249: public static Node selectSingleNode(Node contextNode, String xpath)
250: throws XmlException {
251: // TODO Use the javax XPath API instead
252: NodeList nl = selectNodeList(contextNode, xpath);
253: if (nl.getLength() == 0) {
254: return null;
255: } else {
256: return nl.item(0);
257: }
258: }
259: }
|