Re: jdom 2.0 with generics
Leigh L Klotz Jr <[email protected]>
| Newsgroups | gmane.comp.java.jdom.general |
|---|---|
| Message-ID | <[email protected]> |
It's good to see progress on the Java generics and JDOM after so many
years.
Long ago I implemented a JDOMUtil wrapper of static methods which
applies the various casts, and converted all JDOMException unto
RuntimeException, except for the serialization/parsing code. (There's
really very little reason to handle bad XPath syntax as a checked
exception.)
For example
public static List<Element> selectElements(Document document, String
path);
There's also a neat utility from XForms, called ref, which implements
the XForms first-node rule and text(), with additional defaulting.
/**
* If path is present in element, take the first matching node and
return
* attribute value or element.getTextTrim; otherwise, return default.
* @see
http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static String ref(Element element, XPath path, String def);
SAXParserForJDOM is a workaround for horrible JAXP and Java behavior
with regard to creation of parsers. I'm convinced that one of the
reasons for decline in XML usage is Java's abysmal choices in its API
and classpath-walking which can add hundreds of milliseconds to any XML
operation.
Finally, JaxenXPath exposes what's necessary to add XPath function
definitions.
(I'd like to switch to Saxon9 from Jaxen for JDOM but it's not a nut
I've cracked yet.)
Leigh.
_______________________________________________
To control your jdom-interest membership:
http://www.jdom.org/mailman/options/jdom-interest/[email protected]
JDOMUtil.java
(text/x-java, 24 KB)
import java.net.URL;
import java.util.Map;
import java.util.List;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.regex.Pattern;
import org.jdom.Attribute;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.IllegalDataException;
import org.jdom.Namespace;
import org.jdom.input.DOMBuilder;
import org.jdom.input.SAXBuilder;
import org.jdom.JDOMException;
import org.jdom.output.DOMOutputter;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;
import org.jaxen.Function;
import org.jaxen.XPathFunctionContext;
/**
* Generics and additional interface for JDOM.
*
* For parsing, avoid using JAXP by forcing direct location of the JDK 1.5 implementation of the SAX parser.
* DocumentBuilderFactory is expensive as it searches classpath, and calls
* javax.xml.parsers.FactoryFinder.findJarServiceProvider calls loader.toString
* on the tomcat loader, and that's really expensive as it contains a list of jars.
* See somewhat related bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5047031
*/
public abstract class JDOMUtil {
private static final String SAX_PARSER_CLASSNAME = SAXParserForJDOM.class.getName();
static {
try {
XPath.setXPathClass(JaxenXPath.class);
} catch (JDOMException je) {
throw new RuntimeException(je);
}
}
public static Document jdomParse(String xmlString) throws JDOMException, IOException {
if (xmlString == null || xmlString.equals("")) return null;
SAXBuilder builder = new SAXBuilder(SAX_PARSER_CLASSNAME);
Document document = builder.build(new StringReader(xmlString));
return document;
}
public static Document jdomParse(File file) throws JDOMException, IOException {
SAXBuilder builder = new SAXBuilder(SAX_PARSER_CLASSNAME);
Document document = builder.build(file);
return document;
}
public static Document jdomParse(InputStream is) throws JDOMException, IOException {
SAXBuilder builder = new SAXBuilder(SAX_PARSER_CLASSNAME);
Document document = builder.build(is);
return document;
}
public static Document jdomParse(InputStream is, boolean validation) throws JDOMException, IOException {
SAXBuilder builder = new SAXBuilder(SAX_PARSER_CLASSNAME);
builder.setValidation(validation);
// see http://www.jdom.org/docs/faq.html#a0350
builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
Document document = builder.build(is);
return document;
}
public static Document jdomParse(URL url) throws JDOMException, IOException {
SAXBuilder builder = new SAXBuilder(SAX_PARSER_CLASSNAME);
Document document = builder.build(url);
return document;
}
/**
* @return a String containing an Element's content only, not including its tag, and attributes.
* @see org.jdom.output.outputElementContent
*/
public static String jdomOutputElementContentString(Element element) {
return jdomOutputElementContentString(element, false);
}
/**
* @param pretty true to pretty print
* @return a String containing an Element's content only, not including its tag, and attributes.
* @see org.jdom.output.outputElementContent
*/
public static String jdomOutputElementContentString(Element element, boolean pretty) {
StringWriter sw = new StringWriter();
XMLOutputter outputter = jdomOutputter(pretty);
try {
outputter.outputElementContent(element, sw);
} catch (IOException ioe) {
// StringWriter is actually documented never to throw IOException.
}
return sw.toString();
}
/**
* @return String serialization of document, not pretty printed.
* @see org.jdom.output.outputElementContent
*/
public static String jdomToString(Document document) {
return jdomToString(document, false);
}
/**
* @param pretty true to pretty print
* @return String serialization of document
* @see org.jdom.output.outputElementContent
*/
public static String jdomToString(Document document, boolean pretty) {
return jdomOutputter(pretty).outputString(document);
}
/**
* @param pretty true to pretty print
* @param omitXMLDeclaration true to omit XML Declration
* @return String serialization of document
* @see org.jdom.output.outputElementContent
*/
public static String jdomToString(Document document, boolean pretty, boolean omitXMLDeclaration) {
return jdomOutputter(pretty, omitXMLDeclaration).outputString(document);
}
/**
* @param element
* @param pretty true to pretty print
* @return String serialization of document, not pretty printed.
* @see org.jdom.output.outputElementContent
*/
public static String jdomToString(Element element) {
return jdomToString(element, false);
}
/**
* @param element
* @param pretty true to pretty print
* @return String serialization of document, not pretty printed.
* @see org.jdom.output.outputElementContent
*/
public static String jdomToString(Element element, boolean pretty) {
return jdomOutputter(pretty).outputString(element);
}
/**
* @returns a non-pretty-printing XMLOutputter
*/
public static XMLOutputter jdomOutputter() {
return jdomOutputter(false);
}
/**
* @param pretty true to pretty print
* @returns a new XMLOutputter
*/
public static XMLOutputter jdomOutputter(boolean pretty) {
return jdomOutputter(pretty, false);
}
/**
* Workaround bug in JDOM XMLOutputter defaults.
* In default XMLOutputer, Line separator is \r\n and that causes newlines to grow
* if you parse content that the default XMLOutputter produces.
* @param pretty true to pretty print
* @returns a new XMLOutputter
*/
public static XMLOutputter jdomOutputter(boolean pretty, boolean omitXMLDeclaration) {
Format format = pretty ? Format.getPrettyFormat() : Format.getRawFormat();
// Line separator is normally \r\n which causes newlines to grow when we
// parse this content again.
format.setLineSeparator("\n");
format.setOmitDeclaration(omitXMLDeclaration);
return new XMLOutputter(format);
}
/**
* @param document Document to save
* @param fileName file to write.
* Serializes document to file, non-pretty-printed.
*/
public static void jdomToFile(Document document, String fileName) throws IOException {
jdomToFile(document, fileName, false);
}
/**
* @param document Document to save
* @param fileName file to write.
* @param pretty true to pretty print
* Serializes document to file
*/
public static void jdomToFile(Document doc, String fileName, boolean pretty) throws IOException {
XMLOutputter outputter = jdomOutputter(pretty);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(fileName);
outputter.output(doc, fileOutputStream);
} finally {
try {if (fileOutputStream != null) fileOutputStream.close();} catch (IOException e) {}
}
}
/**
* @param document Document to save
* Serializes document to W3C DOM Document
*/
public static org.w3c.dom.Document jdomToDom(Document document) {
DOMOutputter outputter = new DOMOutputter(org.jdom.adapters.XercesDOMAdapter.class.getName());
try {
return outputter.output(document);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
public static Document domToJDOM(org.w3c.dom.Document document) {
DOMBuilder builder = new DOMBuilder(org.jdom.adapters.XercesDOMAdapter.class.getName());
return builder.build(document);
}
private final static Pattern nonXML10=Pattern.compile("[^\\x09\\x0A\\x0D\\u0020-\\uFFFD]");
/**
* XML 1.0 doesn't allow these characters.
* XML 1.1 allows all but null, but these only as numeric escaped entities.
*/
public static String cleanNonXML10(String s) {
return nonXML10.matcher(s).replaceAll("");
}
/**
* @param e An Element
* @param s A String
* Add String s to Element e as content, but if an IllegalDataException
* occurs because of characters now allowed in XML 1.0, silently remove them.
* XML 1.1 allows all but null, but these only as numeric escaped entities.
*/
public static Element addContentXML10(Element e, String s) {
try {
return e.addContent(s);
} catch (IllegalDataException iex) {
return e.addContent(JDOMUtil.cleanNonXML10(s));
}
}
/**
* Same as XPath.selectNodes(document, path) where all nodes are known to be Elements.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Element> selectElements(Document document, String path) {
try {
return (List<Element>)XPath.selectNodes(document, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(document, path) where all nodes are known to be Attributes.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Attribute> selectAttributes(Document document, String path) {
try {
return (List<Attribute>)XPath.selectNodes(document, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectSingleNode(document, path) where all node is known to be an Element.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Element selectElement(Document document, String path) {
try {
return (Element)XPath.selectSingleNode(document, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(document, path) where all nodes are known to be Content.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Content> selectContents(Document document, String path) {
try {
return (List<Content>)XPath.selectNodes(document, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(element, path) where all nodes are known to be Content.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Content> selectContents(Element element, String path) {
try {
return (List<Content>)XPath.selectNodes(element, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectSingleNode(document, path) where all node is known to be an Attribute.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Attribute selectAttribute(Document document, String path) {
try {
return (Attribute)XPath.selectSingleNode(document, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Uses XPath.selectSingleNode(document, path) where nodes is known to an Attribute,
* then returns either its value or default, if there is no such attribute.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static String selectAttributeValue(Document document, String path, String def) {
Attribute attr;
try {
attr = (Attribute)XPath.selectSingleNode(document, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
if (attr == null) return def;
return attr.getValue();
}
/**
* Uses XPath.selectSingleNode(element, path) where nodes is known to an Attribute,
* then returns either its value or default, if there is no such attribute.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static String selectAttributeValue(Element element, String path, String def) {
Attribute attr;
try {
attr = (Attribute)XPath.selectSingleNode(element, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
if (attr == null) return def;
return attr.getValue();
}
/**
* Same as XPath.selectNodes(element, path) where all nodes are known to be Elements.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Element> selectElements(Element element, String path) {
try {
return (List<Element>)XPath.selectNodes(element, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(element, path) where all nodes are known to be Attributes.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Attribute> selectAttributes(Element element, String path) {
try {
return (List<Attribute>)XPath.selectNodes(element, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectSingleNode(element, path) where all node is known to be an Element.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Element selectElement(Element element, String path) {
try {
return (Element)XPath.selectSingleNode(element, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(element, path) where all nodes are known to be Attributes.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Attribute selectAttribute(Element element, String path) {
try {
return (Attribute)XPath.selectSingleNode(element, path);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(document, path) where all nodes are known to be Attributes.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Attribute> selectAttributes(Document document, XPath path) {
try {
return (List<Attribute>)path.selectNodes(document);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectSingleNode(document, path) where all node is known to be an Element.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Element selectElement(Document document, XPath path) {
try {
return (Element)path.selectSingleNode(document);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(document, path) where all nodes are known to be Attributes.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Attribute selectAttribute(Document document, XPath path) {
try {
return (Attribute)path.selectSingleNode(document);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(document, path) where all nodes are known to be Elements.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Element> selectElements(Document document, XPath path) {
try {
return (List<Element>)path.selectNodes(document);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(element, path) where all nodes are known to be Elements.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Element> selectElements(Element element, XPath path) {
try {
return (List<Element>)path.selectNodes(element);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(element, path) where all nodes are known to be Attributes.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
@SuppressWarnings("unchecked")
public static List<Attribute> selectAttributes(Element element, XPath path) {
try {
return (List<Attribute>)path.selectNodes(element);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectSingleNode(element, path) where all node is known to be an Element.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Element selectElement(Element element, XPath path) {
try {
return (Element)path.selectSingleNode(element);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Same as XPath.selectNodes(element, path) where all nodes are known to be Attributes.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static Attribute selectAttribute(Element element, XPath path) {
try {
return (Attribute)path.selectSingleNode(element);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* If path is present in element, take the first matching node and return
* attribute value or element.getTextTrim; otherwise, return default.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static String ref(Element element, XPath path, String def) {
try {
return refalize(path.selectSingleNode(element), path, def);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* If path is present in document, take the first matching node and return
* attribute value or element.getTextTrim; otherwise, return default.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static String ref(Document element, XPath path, String def) {
try {
return refalize(path.selectSingleNode(element), path, def);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* If path is present in element, take the first matching node and return
* attribute value or element.getTextTrim; otherwise, return default.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static String ref(Element element, String path, String def) {
try {
return refalize(XPath.selectSingleNode(element, path), path, def);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* If path is present in document, take the first matching node and return
* attribute value or element.getTextTrim; otherwise, return default.
* @see http://www.jdom.org/pipermail/jdom-interest/2008-March/016107.html
*/
public static String ref(Document document, String path, String def) {
try {
return refalize(XPath.selectSingleNode(document, path), path, def);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* If node is an Element, return getTextTrim.
* If node is an Attribute, return getValue.
* Otherwse return default.
*/
private static String refalize(Object node, Object path, String def) {
if (node == null) return def;
if (node instanceof Element)
return ((Element)node).getTextTrim();
if (node instanceof Attribute)
return ((Attribute)node).getValue();
return def;
}
@SuppressWarnings("unchecked")
public static List<Element> getElementChildren(Element element) {
return (List<Element>)element.getChildren();
}
@SuppressWarnings("unchecked")
public static List<Element> getElementChildren(Element element, String name) {
return (List<Element>)element.getChildren(name);
}
@SuppressWarnings("unchecked")
public static List<Element> getElementChildren(Element element, String name, Namespace ns) {
return (List<Element>)element.getChildren(name, ns);
}
@SuppressWarnings("unchecked")
public static List<Attribute> getAttributes(Element element) {
return (List<Attribute>)element.getAttributes();
}
/**
* Same as setvalue with Element.
*/
public static void setvalue(Document document, String xpath, String value) {
setvalue(document.getRootElement(), xpath, value);
}
/**
* Given an XPath expression and a String value, sets the leaf-node value of the first node in the resulting nodeset to the
* specified value. If node is neither Attribute nor Element, signals IllegalArgumentException.
* If ignoremissing is false, an IllegalArgumentException will be signalled if the node does not exist.
*/
public static void setvalue(Element element, String xpath, String value, boolean ignoremissing) {
try {
Object node = XPath.selectSingleNode(element, xpath);
if (node == null) {
if (ignoremissing)
return;
else
throw new IllegalArgumentException(String.format("setvalue %s: node not found", xpath));
} else if (node instanceof Element)
((Element)node).setText(value);
else if (node instanceof Attribute)
((Attribute)node).setValue(value);
else
throw new IllegalArgumentException(String.format("setvalue %s: unhandled node class %s ", xpath, node.getClass().getName()));
} catch (JDOMException e) {
throw new RuntimeException("xpath = " + xpath, e);
}
}
/**
* Given an XPath expression and a String value, sets the leaf-node value of the first node in the resulting nodeset to the
* specified value. If node is neither Attribute nor Element, signals IllegalArgumentException.
* If node is missing, signals IllegalArgumentException.
*/
public static void setvalue(Element element, String xpath, String value) {
setvalue(element, xpath, value, false);
}
/**
* Adds all Attributes to the Element. If any is Attribute is already present,
* sets its value.
*
* addAttributes differs from Element.setAttributes in that the setAttributes
* clears the existing attributes first.
*
* @see Element.setAttributes
* @param element the Element
* @param attributes the list of Attributes
*/
public static void addAttributes(Element element, List<Attribute> attributes) {
for (Attribute attribute : attributes) {
element.setAttribute(attribute);
}
}
/**
* Create a new XPath instance, adding the variables from the given Map.
*/
public static XPath newXPathInstance(String xString, Map<String, ?> varMap) {
XPath xpath = newXPathInstance(xString);
for (Map.Entry<String, ?> currEntry : varMap.entrySet()) {
xpath.setVariable(currEntry.getKey(), currEntry.getValue());
}
return xpath;
}
/**
* Create a new XPath instance.
*/
public static XPath newXPathInstance(String xString) {
try {
return XPath.newInstance(xString);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}
/**
* Parses an xsd:boolean into a Java Boolean
* Returns default (which may be null) if value is not a valid xsd:boolean
*/
public static Boolean parseBoolean(String x, Boolean defaultValue) {
if (x != null) {
if (x.equals("0") || x.equals("false")) return false;
if (x.equals("1") || x.equals("true")) return true;
}
return defaultValue;
}
/**
* @throws IllegalArgumentException if value is not a valid xsd:boolean
*/
public static boolean parseBoolean(String x) {
Boolean value = parseBoolean(x, null);
if (value == null) throw new IllegalArgumentException("x is not a valid xsd:boolean");
return value.booleanValue();
}
/**
* Given a map of Jaxen XPath functions, return a new XPath Function context containing those functions.
* If this function context is used in multiple threads, the functions must be thread-safe.
* @return XPathFunctionContext with specified functions
*/
public static XPathFunctionContext newXPathFunctionContext(Map<String, ? extends Function> map) {
XPathFunctionContext xpathFunctionContext = new XPathFunctionContext();
for (Map.Entry<String, ? extends Function> entry : map.entrySet()) {
xpathFunctionContext.registerFunction(null, entry.getKey(), entry.getValue());
}
return xpathFunctionContext;
}
}
SAXParserForJDOM.java
(text/x-java, 1.7 KB)
/**
* Uses NonValidatingConfiguration
*
* JDOM Calls SAXParser.setProperty("http://xml.org/sax/handlers/LexicalHandler")
* which throws SAXNotRecognizedException and then it calls
* SAXParser.setProperty("http://xml.org/sax/handlers/lexical-handler") which works.
*
* This class extends SAXParser and makes the first call succeed. The result
* is a lot fewer exceptions.
*
* Also, if we let Java and Xerces and JDOM decide what configuration to use,
* org.apache.xerces.parsers.SAXParser winds up walking classpath and using
* XIncludeAwareParserConfiguration. Avoid that by picking here, and pick
* org.apache.xerces.parsers.NonValidatingConfiguration while we're at it.
*/
public class SAXParserForJDOM extends org.apache.xerces.parsers.SAXParser {
static {
System.getProperties().put("org.apache.xerces.xni.parser.XMLParserConfiguration",
"org.apache.xerces.parsers.NonValidatingConfiguration");
}
public SAXParserForJDOM() {}
public SAXParserForJDOM(org.apache.xerces.util.SymbolTable symbolTable) { super(symbolTable); }
public SAXParserForJDOM(org.apache.xerces.util.SymbolTable symbolTable, org.apache.xerces.xni.grammars.XMLGrammarPool grammarPool) {
super(symbolTable, grammarPool);
}
public SAXParserForJDOM(org.apache.xerces.xni.parser.XMLParserConfiguration config) {
super(config);
}
public void setProperty(String name, Object object)
throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException {
if ("http://xml.org/sax/handlers/LexicalHandler".equals(name)) {
super.setProperty("http://xml.org/sax/properties/lexical-handler", object);
} else {
super.setProperty(name, object);
}
}
}
JaxenXPath.java
(text/x-java, 12.4 KB)
/*--
Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JDOM" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact <request_AT_jdom_DOT_org>.
4. Products derived from this software may not be called "JDOM", nor
may "JDOM" appear in their name, without prior written permission
from the JDOM Project Management <request_AT_jdom_DOT_org>.
In addition, we request (but do not require) that you include in the
end-user documentation provided with the redistribution and/or in the
software itself an acknowledgement equivalent to the following:
"This product includes software developed by the
JDOM Project (http://www.jdom.org/)."
Alternatively, the acknowledgment may be graphical using the logos
available at http://www.jdom.org/images/logos.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
This software consists of voluntary contributions made by many
individuals on behalf of the JDOM Project and was originally
created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
on the JDOM Project, please see <http://www.jdom.org/>.
*/
import java.util.List;
/*
import org.jaxen.*;
import org.jaxen.jdom.*;
import org.jdom.*;
*/
import org.jaxen.Function;
import org.jaxen.FunctionContext;
import org.jaxen.JaxenException;
import org.jaxen.SimpleFunctionContext;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.SimpleVariableContext;
import org.jaxen.XPathFunctionContext;
import org.jaxen.jdom.JDOMXPath;
import org.jdom.Attribute;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.xpath.XPath;
public class JaxenXPath extends XPath {
/**
* The compiled XPath object to select nodes. This attribute can
* not be made final as it needs to be set upon object
* deserialization.
*/
private transient JDOMXPath xPath;
/**
* The current context for XPath expression evaluation.
*/
private Object currentContext;
/**
* Creates a new XPath wrapper object, compiling the specified
* XPath expression.
*
* @param expr the XPath expression to wrap.
*
* @throws JDOMException if the XPath expression is invalid.
*/
public JaxenXPath(String expr) throws JDOMException {
setXPath(expr);
}
/**
* Adds a function definition to the list functions known of
*
* @param namespaceURI the function namespace.
* @param localName the function localname.
* @param Function function.
*/
public void registerFunction(String namespaceURI, String localName, Function function)
throws JDOMException {
FunctionContext functionContext = xPath.getFunctionContext();
// can't set the FunctionContext to be SimpleFunctionContext because
// functions like 'not' won't be recognized. just make sure that it's a context
// that supports registerFunction
if (functionContext instanceof SimpleFunctionContext)
((SimpleFunctionContext)functionContext).registerFunction(namespaceURI, localName, function);
else
throw new JDOMException("Invalid type of function context: " + functionContext.getClass().getName());
}
/**
* Evaluates the wrapped XPath expression and returns the list
* of selected items.
*
* @param context the node to use as context for evaluating
* the XPath expression.
*
* @return the list of selected items, which may be of types: {@link Element},
* {@link Attribute}, {@link Text}, {@link CDATA},
* {@link Comment}, {@link ProcessingInstruction}, Boolean,
* Double, or String.
*
* @throws JDOMException if the evaluation of the XPath
* expression on the specified context
* failed.
*/
public List selectNodes(Object context) throws JDOMException {
try {
currentContext = context;
return xPath.selectNodes(context);
}
catch (JaxenException ex1) {
throw new JDOMException("XPath error while evaluating \"" +
xPath.toString() + "\": " + ex1.getMessage(), ex1);
}
finally {
currentContext = null;
}
}
/**
* Evaluates the wrapped XPath expression and returns the first
* entry in the list of selected nodes (or atomics).
*
* @param context the node to use as context for evaluating
* the XPath expression.
*
* @return the first selected item, which may be of types: {@link Element},
* {@link Attribute}, {@link Text}, {@link CDATA},
* {@link Comment}, {@link ProcessingInstruction}, Boolean,
* Double, String, or <code>null</code> if no item was selected.
*
* @throws JDOMException if the evaluation of the XPath
* expression on the specified context
* failed.
*/
public Object selectSingleNode(Object context) throws JDOMException {
try {
currentContext = context;
return xPath.selectSingleNode(context);
}
catch (JaxenException ex1) {
throw new JDOMException("XPath error while evaluating \"" +
xPath.toString() + "\": " + ex1.getMessage(), ex1);
}
finally {
currentContext = null;
}
}
/**
* Returns the string value of the first node selected by applying
* the wrapped XPath expression to the given context.
*
* @param context the element to use as context for evaluating
* the XPath expression.
*
* @return the string value of the first node selected by applying
* the wrapped XPath expression to the given context.
*
* @throws JDOMException if the XPath expression is invalid or
* its evaluation on the specified context
* failed.
*/
public String valueOf(Object context) throws JDOMException {
try {
currentContext = context;
return xPath.stringValueOf(context);
}
catch (JaxenException ex1) {
throw new JDOMException("XPath error while evaluating \"" +
xPath.toString() + "\": " + ex1.getMessage(), ex1);
}
finally {
currentContext = null;
}
}
/**
* Returns the number value of the first item selected by applying
* the wrapped XPath expression to the given context.
*
* @param context the element to use as context for evaluating
* the XPath expression.
*
* @return the number value of the first item selected by applying
* the wrapped XPath expression to the given context,
* <code>null</code> if no node was selected or the
* special value {@link java.lang.Double#NaN}
* (Not-a-Number) if the selected value can not be
* converted into a number value.
*
* @throws JDOMException if the XPath expression is invalid or
* its evaluation on the specified context
* failed.
*/
public Number numberValueOf(Object context) throws JDOMException {
try {
currentContext = context;
return xPath.numberValueOf(context);
}
catch (JaxenException ex1) {
throw new JDOMException("XPath error while evaluating \"" +
xPath.toString() + "\": " + ex1.getMessage(), ex1);
}
finally {
currentContext = null;
}
}
/**
* Defines an XPath variable and sets its value.
*
* @param name the variable name.
* @param value the variable value.
*
* @throws IllegalArgumentException if <code>name</code> is not
* a valid XPath variable name
* or if the value type is not
* supported by the underlying
* implementation
*/
public void setVariable(String name, Object value)
throws IllegalArgumentException {
Object o = xPath.getVariableContext();
if (o instanceof SimpleVariableContext) {
((SimpleVariableContext)o).setVariableValue(null, name, value);
}
}
/**
* Adds a namespace definition to the list of namespaces known of
* this XPath expression.
* <p>
* <strong>Note</strong>: In XPath, there is no such thing as a
* 'default namespace'. The empty prefix <b>always</b> resolves
* to the empty namespace URI.</p>
*
* @param namespace the namespace.
*/
public void addNamespace(Namespace namespace) {
try {
xPath.addNamespace(namespace.getPrefix(), namespace.getURI());
}
catch (JaxenException ex1) { /* Can't happen here. */ }
}
/**
* Returns the wrapped XPath expression as a string.
*
* @return the wrapped XPath expression as a string.
*/
public String getXPath() {
return (xPath.toString());
}
/**
* Compiles and sets the XPath expression wrapped by this object.
*
* @param expr the XPath expression to wrap.
*
* @throws JDOMException if the XPath expression is invalid.
*/
private void setXPath(String expr) throws JDOMException {
try {
xPath = new JDOMXPath(expr);
xPath.setNamespaceContext(new NSContext());
}
catch (Exception ex1) {
throw new JDOMException(
"Invalid XPath expression: \"" + expr + "\"", ex1);
}
}
public void setFunctionContext(XPathFunctionContext xpathFunctionContext) {
xPath.setFunctionContext(xpathFunctionContext);
}
public String toString() {
return (xPath.toString());
}
public boolean equals(Object o) {
if (o instanceof JaxenXPath) {
JaxenXPath x = (JaxenXPath)o;
return (super.equals(o) &&
xPath.toString().equals(x.xPath.toString()));
}
return false;
}
public int hashCode() {
return xPath.hashCode();
}
private class NSContext extends SimpleNamespaceContext {
public NSContext() {
super();
}
/**
* <i>[Jaxen NamespaceContext interface support]</i> Translates
* the provided namespace prefix into the matching bound
* namespace URI.
*
* @param prefix the namespace prefix to resolve.
*
* @return the namespace URI matching the prefix.
*/
public String translateNamespacePrefixToUri(String prefix) {
if ((prefix == null) || (prefix.length() == 0)) {
return null;
}
String uri = super.translateNamespacePrefixToUri(prefix);
if (uri == null) {
Object ctx = currentContext;
if (ctx != null) {
Element elt = null;
// Get closer element node
if (ctx instanceof Element) {
elt = (Element)ctx;
} else if (ctx instanceof Attribute) {
elt = ((Attribute)ctx).getParent();
} else if (ctx instanceof Content) {
elt = ((Content) ctx).getParentElement();
} else if (ctx instanceof Document) {
elt = ((Document)ctx).getRootElement();
}
if (elt != null) {
Namespace ns = elt.getNamespace(prefix);
if (ns != null) {
uri = ns.getURI();
}
}
}
}
return uri;
}
}
}