I am setting the parameter like this:
Document doc_23 = createDocument(doc_bytes);
XPathExpression xpe = XPathFactory.newInstance().newXPath().compile("/");
transformer.setParameter("document23",xpe.evaluate(doc_23, XPathConstants.NODESET));
I also tried this:
transformer.setParameter("document23",new StreamSource(new StringReader(xml_text)));
In my xslt i am getting the variable like this:
<xsl:variable name="document23" select="/.."></xsl:variable>
And try to use it:
<xsl:for-each select="$document23//Product">
<xsl:message>Test<xsl:value-of select="generalDetails/productCode"/></xsl:message>
</xsl:for-each>
But i dont work (the for-each never get enterd).
The document have the elements speciffied beacasue using 'document(document23.xml)//Product' does work.
Thanks for the help.
You're using the DOM and JAXP APIs, which isn't an ideal way of using Saxon: the DOM is very slow with Saxon, and the JAXP XPath API is very weakly-typed so you need to have the interface specification and the Saxon-specific details both to hand in order to use it successfully. So my first recommendation would be, if you're committed to Saxon then you would be better off using the s9api API in preference.
In fact I don't understand why you are using XPath interfaces at all. You seem to be trying to run the XPath expression "/", which returns whatever you supply as the input. That's completely pointless.
If you do want to use the JAXP transformation API (and therefore setParameter()), the kind of things you can supply are described here:
http://www.saxonica.com/documentation/index.html#!using-xsl/embedding/jaxp-transformation
In particular see the paragraph that starts "The types of object that can be supplied as stylesheet parameters ..." This links to the "Extensibility" section, which tells you
"If the [...] value is an instance of javax.xml.transform.Source (other than a NodeInfo), a tree is built from the specified Source object, and the root node of this tree is returned as the result of the function."
So you can supply a StreamSource or a DOMSource to the setParameter() method as in your example.
If the path expression in an xsl:for-each appears to be selecting nothing, use xsl:message or xsl:copy-of to display the document you are trying to select into; this will often give you a clue what is wrong.
I see one problem, mainly that you have used <xsl:variable name="document23" select="/.."></xsl:variable>, if you want to define an external parameter then you need to use <xsl:param name="document23" select="/.."/>, not xsl:variable.
Related
Is it possible to inject a namespace into an XSLT document so that (for instance) the value of a string is used to specify a namespace? I know that it is similarly possible to declare attributes and elements (for instance) using the <xsl:attribute/> and <xsl:element/> constructs, respectively. Is there a similar construct for namespaces?
The reason why I ask for this is that I want to construct an XSLT transformation for constructing an XML request used across a number of vendors that accepts the same XML structure (except that they apply different namespaces).
I use the Saxon XSLT processor.
Easily done in XSLT 2.0 using xsl:namespace.
If you really need to do it in XSLT 1.0 (why?), there's a tortuous workaround:
<xsl:variable name="temp">
<xsl:element name="{$prefix}:dummy" namespace="{$uri}"/>
</xsl:variable>
<xsl:copy-of select="exsl:node-set($temp//*/namespace::*)"/>
In XSLT 2 and later there is xsl:namespace (https://www.w3.org/TR/xslt-30/#creating-namespace-nodes) of course, I am not sure however it will help to deal with input from different namespaces as, like xsl:element, it creates result nodes.
And don't forget that both xsl:element and xsl:attribute allow you to construct result nodes in a different namespace using the namespace attribute.
There is *:foo to select or match foo elements in any namespace.
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.
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.
Let's say I have a doc.xml and corresponding doc.xsd. I use xpath to retrieve some nodes, so I get a list of org.w3c.dom.Node. How can I get type of each node from schema, eg. xs:integer, xs:string etc ?
Some solution would be to parse schema with xpath query "//NodeName[#type]" using node.getNodeName() as NodeName, but that's not perfect. I can't be sure that schema is elegant - what if NodeName exists in many places in schema and has not been extracted as a separate type?
So generally I am looking for a reliable solution to get the node type for ANY valid xml & xsd.
You should consider using JAXB. It will create Java classes for you based on the schema type. Then your XML docs are read into those classes, which are typed according to how you defined your XSD. Therefore xsd:int maps to java int(or Integer wrapper class, I can't recall), etc.
Cast your DOM Elements to TypeInfo: from there, you can access the type information you're looking for.
Unfortunately types as defined in an XML Schema (XSD) or Document Type Definition (DTD) are not directly tied to XML document they validate. The elements and attributes in an XML document do not inherently have a type they are just text. Think of an XSD as a script that validates an XML document rather than a set of type annotations for elements and attributes.
The XML specification does not define types as you are thinking of them here. Even Document Type Definitions (DTD) which can be embedded inside XML documents more about the structure of the document not the type of the data contained in elements and attributes.
The type system described in XML Schema is an optional layer of validation that can be applied to XML documents. Since this validation optional the standard XML APIs do not provide a way to bind the validation rules in an XSD to the actual attributes and elements.
I think it would be possible for an XML API to provide a mechanism to bind an XSD to a specific XML document, but I am not aware of an XML parser that does this. One reason why this is not so easy is that the type system that is defined in XML Schema is much richer than is supported in most mainstream programming languages. In your example you may only be interested in xs:integer, xs:string and the like but in XML Schema you can create types that specify ranges, patterns and other things that are just not possible with data types in most programming languages. To represent this complex type system in Java or any programming language would have to be done through a fairly complex API. The the question becomes it is really worth it? I would say probably not.
As per David Ds answer, slightly cleaner, call getSchemaTypeInfo() on an element or attribute
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