Execute XPath 3.1 on Java map - java

I am upgrading from XPath 1.0 to XPath 3.1. I used the library javax.xml.xpath for XPath 1.0 and am now using the Saxon-HE library. It was fairly straightforward to migrate the code and I used the S9API interface for the evaluation of the expressions as suggested by saxon.
There is however one little part of code that I can not seem to figure out how to migrate:
public static Object getXpathValueFromContentMap(String name, Map<String, Object> content, boolean list) {
try {
if (list) {
return newArrayList(JXPathContext.newContext(content).iterate(name));
} else {
return JXPathContext.newContext(content).getValue(name);
}
} catch (JXPathNotFoundException ignore) {
return null;
}
}
This method evalutes an xpath expression on a map. Can this be done using the saxon library and if so, how?

JXPath (which I haven't come across before) appears to be an implementation of XPath 1.0 over (an XML node view of) Java data structures such as maps and arrays.
Saxon doesn't have anything similar. With XPath 3.1 it would be much more appropriate to interpret Java maps and arrays as XPath 3.1 maps and arrays, rather than going via an XML node view. However, the XPath expressions for doing that will be significantly different.
It's theoretically possible to provide an XML mapping in Saxon over an external data structure but it's a significant amount of work and that doesn't seem the right approach. But it rather depends on how much XPath code you've got that needs converting.

Related

How to compile schematron conditions (XPaths/XSLT 2.0) in Java

I want to validate from Java code a schematron condition (which is in the end a xslt boolean evaluation) to know if it is syntactically correct. Our users can provide extra validation rules that we will transform into schematron to validate given XML files, but we want to know if these rules make sense in the end.
I have tried with method compile from javax.xml.xpath.XPath, but seems to lack things like 'castable as' and other default xslt2.0 functions/operators. I've tried to provide a default XPathFuntionResolver to tell the XPath to ignore the functions, but didn't seem to do the trick.
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setXPathFunctionResolver(new XPathFunctionResolver() {
#Override
public XPathFunction resolveFunction(QName functionName, int arity) {
return new XPathFunction() {
#Override
public Object evaluate(List args) throws XPathFunctionException {
return null;
}
};
}
});
Which is the best way to validate those user defined rules?
The default implementation of javax.xml.xpath.XPath in the JDK only supports XPath 1.0, but your particular XPath expressions are XPath 2.0 (or later). There are several third-party implementations of XPath 2.0 available for the Java platform, the Saxon product (mine) is the best known.
You can use Saxon's XPath engine using the standard javax.xml.xpath.XPath API, as Martin Honnen suggests; however the API is designed around XPath 1.0 so it can be tricky to exploit the full functionality of XPath 2.0 (for example, you can't easily evaluate an expression that returns a date). So Saxon has an alternative API called s9api, which is probably easier to use. For details the Saxon documentation is at www.saxonica.com.
Your approach of using a custom function resolver isn't going to help the XPath 1.0 engine understand syntactic constructs like "X castable as Y" - it's only used to resolve function calls.

XML formatted Java string manipulation

I'm developing a plugin that has node(computer) objects with attributes like:
String name
String description
String labels
Launcher computerLauncher
...
I can convert the node(computer) object to an XML-formated String like:
String xml = jenkins.instance.toXML(node);
Which gives me a string:
<name>Computer1</name>
<description>This is a description</description>
<labels>label1 label2</labels>
<launcher>windows.object.launcher.12da1</launcher>
Then I can go the other way back:
Node node = jenkins.instance.fromXML(xml);
I have no methods for changing attributes in a Node so I want to convert it to XML, change som attributes and then make it a Node again.
I see two options
Manipulate the XML with some String methods to replace everything in between the <> tags.
Try to cast the XML string to something like a real Object and manipulate it that way.
Not sure what would be the best approach.
Why invent something new when there already is support for all that using Java's DOM (Document Object Model) API?
Use a DocumentBuilderFactory to get a DocumentBuilder and create a Document instance. With this you can create the 'Node' objects (please note that the example you posted is actually not valid XML, it's missing a root node) in your toXML method, serializing the Document to a String could be done by using a Transformer.
With the DOM API you can also modify the attributes of your existing elements.
Parsing the Document instance from an XML string is realized again with the help of the DocumentBuilder, using DocumentBuilder#parse.
If your DOM operations are not too complex this should be a nice, quick way to accomplish your goal.
It makes sense to me to use a DOM-like approach. But don't use DOM itself: there are much better alternatives like JDOM and XOM that have much friendlier APIs.
recenty I had to manipulate large XML files (my software had to create some XML files dynamically and get input data from some other XML files). To do this I've used JAXB, which is a very neat API that marshalls XML files into Java objects and Java objects into XML files automatically.
However to do this I had to create a XSD file to specify the XMLs that I would need to read and write from.
Therefore JAXB requires more work to set up than DOM, so if your needs are simple I suggest that you use DOM, however if your needs are more complex, then I would suggest JAXB.

XPath 1.0 queries on JAXB objects?

JAXB has been great, a real timesaver, but it's still really time consuming to traverse the resulting object trees; almost as bad as working directly with the DOM.
Is there a way that I can do XPath 1.0 queries on a JAXBElement, without having to painstakingly marshal the document to and from a DOM model each time?
Not directly, no. However, you can use Apache Commons Jxpath, which allows you to run XPath queries across arbitrary object graphs, not just JAXB-bound ones. It can be run in "lenient" mode, which is tolerant of nulls.
Extremely handy for replacing those NPE-prone graph navigations.
The accepted answer was from 2010 and this post is for the benefit of others who are looking to use XPath with JAXB. Moxy implementation provides lots of nice extensions and one of them is to execute XPath. Read more about this on Moxy's tutorial. Example copied from the same place
Customer customer = (Customer) jaxbContext.createUnmarshaller().unmarshal(instanceDoc);
...
int customerId = jaxbContext.getValueByXPath(customer, "#id", null, Integer.class);
jaxbContext.setValueByXPath(customer, "first-name/text()", null, "Bob");
jaxbContext.setValueByXPath(customer, "phone-number/area-code/text()", null, "555");
...
jaxbContext.createMarshaller().marshal(customer, System.out);

Simple way to do Xml in Java

Is there is Simple way to read and write Xml in Java?
I've used a SAX parser before but I remember it being unintuitive, I've looked at a couple of tutorials for JAXB and it just looks complicated.
I don't know if I've been spoilt by C#'s XmlDocument class, but All I want to do is create an Xml Document that represents a a set of classes and their members (some are attributes some are elements).
I would look into serialization but the XML has to have the same format as the output of a c# app which I am reverse engineering into Java.
I recommend XOM. Its API is clear and intuitive.
You should check out Xstream. There is a 2 minute tutorial that is really simple. To get the same format, you would model the classes the same.
If you are using jdk 1.4 or newer take a look at XMLEncoder class.
Some of the more popular approaches to consider:
Java Archictecture for XML Binding
JAXB is a specification for a standard XML binding. If you already have an XSD, it can generate your Java classes for you, and then all that's left is to use a standard API for marshalling/unmarshalling.
Reference implementation from Glassfish
Apache's implementation JaxMe
Other binding approaches
As with JAXB, these approaches use XML-based binding configurations. They may provide more fine grained control of the unmarshalling process.
Castor
JIBX
Roll your own
Using StAX
Using XOM
Using plain XPath
Dom4j is a simple api for creating xml documents in java.
Document document = DocumentHelper.createDocument();
Element root = document.addElement( "root" );
Element author2 = root.addElement( "author" )
.addAttribute( "name", "Toby" )
.addAttribute( "location", "Germany" )
.addText( "Tobias Rademacher" );
The most simple way so far is the MarkupBuilder in Groovy. Think of Groovy as a new syntax for Java. The XmlSlurper can be used to read XML.
I think that Apache XMLBeans provides the functionality you are after.
The Wikipedia page gives a good overview and example usage.
There is a wide choice of XML processing options for Java, though judging from the .NET documentation for XmlDocument, the Java DOM implementation is the closest out-of-the-box equivalent.
.NET XmlDocument:
This class implements the W3C Document
Object Model (DOM) Level 1 Core and
the Core DOM Level 2.
Java Document:
See also the Document Object Model (DOM) Level 3 Core Specification.
Sample code:
public static void main(String[] args) throws Exception {
File xmlFile = new File(".classpath");
// read it
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(xmlFile);
// walk it
System.out.println("Node count=" + countNodes(document));
// write it
Source source = new DOMSource(document);
Result result = new StreamResult(System.out);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(source, result);
}
/** Doesn't count attributes, etc */
private static int countNodes(Node node) {
int count = 0;
NodeList kids = node.getChildNodes();
count += kids.getLength();
for (int i = 0; i < kids.getLength(); i++) {
count += countNodes(kids.item(i));
}
return count;
}
I think JAXB is only complicated if you look at wrong examples. Specifically, yes, schema-based way can get messy. But code-first, annotation-based is trivially easy.
Another easy alternative is XStream. And for non-binding case, StaxMate, which is an add-on for streaming Stax parsers.
If SAX parsing is mandatory, JAXP is a good choice. I prefer DOM parsing and use jdom which seems a lot easier to me.
I would certainly use XOM if you want a DOM-like approach and SAX (www.sax.org) if you want a SAX-like approach. I was involved in the early development of XML and SAX was developed as an event-driven approach, which is useful for some applications. DOM/XOM and SAX are complementary - sometimes you need one, sometimes the other. If you wish to build objects as you go rather than read everything into memory, use SAX. If you are happy to read everything in and then process it, use XOM.
I spent far too much time trying to get the W3C DOM to work - IMO it is poorly defined with too many ways of doing some things and not enough for others. When XOM came it revolutionised my productivity.
The XOM community is very knowledgeable and focused and helpful.

JAVA: Build XML document using XPath expressions

I know this isn't really what XPath is for but if I have a HashMap of XPath expressions to values how would I go about building an XML document. I've found dom-4j's
DocumentHelper.makeElement(branch, xpath) except it is incapable of creating attributes or indexing. Surely a library exists that can do this?
Map xMap = new HashMap();
xMap.put("root/entity/#att", "fooattrib");
xMap.put("root/array[0]/ele/#att", "barattrib");
xMap.put("root/array[0]/ele", "barelement");
xMap.put("root/array[1]/ele", "zoobelement");
would result in:
<root>
<entity att="fooattrib"/>
<array><ele att="barattrib">barelement</ele></array>
<array><ele>zoobelement</ele></array>
</root>
I looked for something similar a few years ago - a sort of writeable XPath. In the end, having not found anything, I hacked up something which essentially built up the XML document by adding new nodes to parent expressions:
parent="/" element="root"
parent="/root" element="entity"
parent="/root/entity" attribute="att" value="fooattrib"
parent="/root" element="array"
parent="/root" element="ele" text="barelement"
(This was itself to be governed by an XML configuration file, hence the appearance of above.)
It would be tempting to try an automate some of this to just take the last path element, and make something of it, but I always felt that there were XPath expressions I could write which such a dumbheaded approach would get wrong.
Another approach I considered, though did not implement (the above was "good enough"), was to use the excellent Jaxen to generate elements that did not exist, on the fly if it didn't already exist.
From the Jaxen FAQ:
The only thing required is an implementation of the interface org.jaxen.Navigator. Not all of the interface is required, and a default implementation, in the form of org.jaxen.DefaultNavigator is also provided.
The DOMWriterNavigator would wrap and existing DOMNavigator, and then use the makeElement method if the element didn't exist. However, even with this approach,
you'd probably have to do some pre/post processing of the XPath query for things like attributes and text() functions.
The best I was able to come up with is to use a JAXB implementation, which will marshall/unmarshal objects to xml and then I used Dozer (http://dozer.sourceforge.net/documentation/mapbackedproperty.html) to map the xpaths which were keys in a map to the JAXB object method setters.
<mapping type="one-way" map-id="TC1">
<class-a>java.util.Map</class-a>
<class-b>org.example.Foo</class-b>
<field>
<a key="root/entity/#att">this</a>
<b>Foo.entity.att</b>
<a-hint>java.lang.String</a-hint>
</field>
It's more of a two step solution, but really worked for me.
I also wanted same kind of requirement where nature is so dynamic and dont want to use XSLT or any object mapping frameworks, so i've implemented this code in java and written blog on it please visit,
http://ganesh-kandisa.blogspot.com/2013/08/dynamic-xml-transformation-in-java.html
or fork code at git repository,
https://github.com/TheGanesh/DynamicXMLTransformer

Categories