Pass document as parameter to XSL Translation in J

2019-02-17 03:19发布

问题:

I'm working on addition internationalization to my XSL. I've seen plenty of examples of creating a dictionary.xml file and loading it into my XSL via document('dictionary.xml'). I want to do something similar, but I don't want to create and store the dictionary.xml file on disk, I'd rather build it from SQL at server startup and keep the Document object in memory in Java. I'd like to then pass the dictionary document as a parameter to the transformer so that my XSL translation function can use it. However, it doesn't seem to be working.

Relevant Java code:

Document dictionary = TranslationDictionary.getDictionaryDocument();
transformer.setParameter("dictionary", dictionary);

The dictionary document content:

<dictionary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <translatedString dictionaryId="BASIC_DETAILS">
        <language id="es" value="Detalles B&#225;sicos"/>
    </translatedString >
    <translatedString dictionaryId="VEHICLE_INFORMATION">
        <language id="es" value="Informaci&#243;n del Veh&#237;culo"/>
    </translatedString >
    <translatedString dictionaryId="STRUCTURE">
        <language id="es" value="Estructura"/>
    </translatedString >
    <translatedString dictionaryId="DRIVER_INFORMATION">
        <language id="es" value="Informaci&#243;n del Conductor"/>
    </translatedString >
    <translatedString dictionaryId="MAINTENANCE_AND_FEUL">
        <language id="es" value="Mantenimiento &amp; Combustible"/>
    </translatedString >
    <translatedString dictionaryId="PURCHASING">
        <language id="es" value="Compra"/>
    </translatedString >
</dictionary>

The XSL file:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:dc="http://www.test.com">
    <xsl:param name="dictionary"/>
    <xsl:param name="language" select="'es'"/>


<xsl:template match="/">
<xsl:message>
    <xsl:copy-of select="$dictionary/dictionary/translatedString[@dictionaryId='BASIC_DETAILS']/language[@id='es']/@value"/>
</xsl:message>

</xsl:template>

But I get nothing. I've tried just doing a copy of $document/document to confirm that I'm not having an xpath issue, and its not that, because that gives me a copy of the full document. It's as if the XSL is seeing $dictionary as a string instead of a node. Any clues?

回答1:

Ok, I made a skeleton copy of your code. This is going to sound bizarre, but after you create your dictionary document in the java code, and before you set it as a parameter for the transformer, just invoke the method:

dictionary.getDocumentElement();

then it works! Looks like a bug in the way saxon is handling a parameter thats a document, where it requires some kind of initialisation which hasnt been done ? I'm not digging into the debugger.



回答2:

Use a URIResolver instead of a parameter. First, create the resolver like this:

public class DocURIResolver implements URIResolver {

    final Map<String, Document> documents;

    public DocURIResolver(final Map<String, Document> documents) {
        this.documents = documents;
    }

    public Source resolve(final String href, final String base) {
        final Document doc = documents.get(href);
        return (doc != null) ? new DOMSource(doc) : null;
    }
}

Use it like this:

Document dictionary = TranslationDictionary.getDictionaryDocument();
Map<String, Document> docs = new HashMap<String, Document>();
docs.put("dictionary", dictionary);
// transformer is your javax.xml.transform.Transformer
transformer.setURIResolver(new DocURIResolver(docs));

And reference it in your stylesheet by name:

<xsl:variable name="dict" select="document('dictionary')"/>

This is just a toy example, of course. You can make your URIResolver as full-featured as necessary.



回答3:

Passing a DOM Document node as a parameter to a Saxon transformation should work (DOM is not the most efficient tree representation, by a long way, but it should work). So should passing DOMSource that wraps the DOM Document. I usually start by doing xsl:copy-of select="$doc", and you seem to have done this and confirmed that the value is being passed in correctly. If you're not getting anything in response to XPath selections within the document, this usually means that the XPath expressions are wrong. The most usual reasons are forgetting about the root (document) node, and forgetting about namespaces. But I'm afraid there's no evidence of such mistakes in the code you have shown us - assuming the DOM reflects the XML you have shown in your post.

Your post suggests that you have build the DOM Document programmatically. It's possible that you have created a DOM that Saxon can't process for some reason: DOM interfaces are not very robust and there are sometimes difficulties when people use a DOM implementation that hasn't been tested with Saxon.

You could also test your stylesheet by running it from the command line - you can supply the value of the $dictionary parameter using +dictionary=dict.xml (the leading '+' causes it to be recognized as the name of a file that needs to be parsed).



回答4:

Does changing

select="$dictionary

to

select="node-set($dictionary)

help ?



标签: java xslt