In my XSLT, I have a variable which contains a string. This string contains a fragment of XML. This is coming in programmatically, but its the equivalent of this:
<xsl:variable name="xmlfrag" select="'<foo>this <bar>is</bar> it</foo>'"/>
Is there a way to parse this XML and add it to the output? We're using SAXON for Java.
Use the saxon:parse()
extension function.
The Dimitre solution requires a licensed version of Saxon.
Here is another solution that works also with the free version of Saxon.
I've tried it successfully with Saxon HE 9.5.X.
The inverse process is documented here.
It is about registering a custom extension function with these contents:
import net.sf.saxon.expr.XPathContext; import net.sf.saxon.lib.ExtensionFunctionCall; import net.sf.saxon.lib.ExtensionFunctionDefinition; import net.sf.saxon.om.Sequence; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.s9api.DocumentBuilder; import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import javax.xml.transform.stream.StreamSource; import java.io.StringReader; @SuppressWarnings("serial") public class XmlParser extends ExtensionFunctionDefinition { @Override public StructuredQName getFunctionQName() { return new StructuredQName("vis", URI, "my.custom.uri"); } @Override public SequenceType[] getArgumentTypes() { return new SequenceType[] { SequenceType.SINGLE_STRING }; } @Override public SequenceType getResultType(SequenceType[] sequenceTypes) { return SequenceType.NODE_SEQUENCE; } @Override public ExtensionFunctionCall makeCallExpression() { return new ExtensionFunctionCall() { DocumentBuilder constructor; @Override public Sequence call(XPathContext ctx, Sequence[] secs) throws XPathException { // Not synchronized, as worst case it initialize twice if (constructor == null) constructor = new Processor(ctx.getConfiguration()).newDocumentBuilder(); String xml = secs[0].head().getStringValue(); try { return constructor.build(new StreamSource(new StringReader(xml))).getUnderlyingNode(); } catch (SaxonApiException e) { final int max = 500; String xml2 = xml.length() > 500 ? xml.substring(0, max)+"..." : xml; throw new XPathException("Error when parsing XML.\n"+xml2, e); } } }; } }
You can use this function as follows:
<xs:value-of xmlns:vis="my.custom.uri" select="vis:parse-xml('<a>Test</a>')"/>