简体   繁体   中英

Passing a XML File (InputStream) to XSLT avoid using Document in XSLT javax.xml

I am new to XML, XSLT and javax.xml

Currently my objective is to merge two XML files using XSLT Version 1.0 and everything works fine.

But I feel that there is a limitation in my code and I would like to get rid of it, if possible.

These are my resources: 'file1.xml' 'file2.xml' 'merge.xslt'

This is my merge method:

public ByteArrayOutputStream merge(final InputStream file1) {
    final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    final TransformerFactory tFactory = TransformerFactory.newInstance();
    Transformer transformer;
    try {
        transformer = tFactory.newTransformer(new StreamSource("merge.xslt"));
        transformer.transform(new StreamSource(file1), new StreamResult(outputStream));
    } catch (final TransformerConfigurationException e) {
        LOG.warn("Problem occurred transforming files configuration issue", e);
    } catch (final TransformerException e) {
        LOG.warn("Problem occurred transforming files", e);
    }
    return outputStream;
}

This is how I am passing file2.xml inside the XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="lookup" select="document('/file2.xml')"/>

<xsl:template match="/">
  Do the processing how I want
</xsl:template>
</xsl:stylesheet>

What I want to achieve is that, I would like to modify my merge method to pass file1.xml and file2.xml.

public ByteArrayOutputStream merge(final InputStream file1,final InputStream file2)

And I want to somehow pass this InputStream file2 to the XSLT, so that the limitation of reading the file from file system is eliminated.

Can someone guide me if this is possible and how to achieve it, I would really appreciate all the help.

Thank you.

I tried a small example, referred here XSLT Processing with Java : passing xml content in parameter But it didn't work for me.

final InputStream file1 = new FileInputStream("file1.xml");
    final InputStream file2 = new FileInputStream("file2.xml");
    final TransformerFactory tFactory = TransformerFactory.newInstance();
    Transformer transformer;
    transformer = tFactory.newTransformer(new StreamSource("merge.xslt"));
    transformer.setParameter("lookup", new StreamSource(file2));
    transformer.transform(new StreamSource(file1), new StreamResult(new FileOutputStream("test.xml")));

And updated the XSLT as follows:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="lookup"/>

<xsl:template match="/">
  Do the processing how I want
</xsl:template>
</xsl:stylesheet>

Error that I am getting is as follows:

ERROR:  'Invalid conversion from 'javax.xml.transform.stream.StreamSource' to 'node-set'.'
Exception in thread "main" javax.xml.transform.TransformerException: java.lang.RuntimeException: Invalid conversion from 'javax.xml.transform.stream.StreamSource' to 'node-set'.
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:755)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:359)

Also Using :

<xsl:param name="lookup"/>

Will I get access to file2.xml inside the XSLT.

After doing a lot of research and reading different posts and blogs, I was finally able to resolve my issue.

I referred the questions asked here and got the idea for doing this.

Pass document as parameter to XSL Translation in Java

The other solutions suggested in this thread didn't workout for me.

Here is what I did,

Used a URIResolver instead of parameter.

public class DocumentURIResolver implements URIResolver {

final Map<String, Document> _documents;

public DocumentURIResolver(final Map<String, Document> documents) {
    _documents = documents;
}

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

This is how I modified my method:

public ByteArrayOutputStream merge(final InputStream file1,final InputStream file2) {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer;
try {
    transformer = tFactory.newTransformer(new StreamSource("merge.xslt"));
    final DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    final Document documentFile = db.parse(file2);
    Map<String, Document> docs = new HashMap<String, Document>();
    docs.put("lookup", documentFile);
    transformer.setURIResolver(new DocURIResolver(docs));
    transformer.transform(new StreamSource(file1), new StreamResult(outputStream));
} catch (final TransformerConfigurationException e) {
    LOG.warn("Problem occurred transforming files configuration issue", e);
} catch (final TransformerException e) {
    LOG.warn("Problem occurred transforming files", e);
}
return outputStream;
}

And this is how I refereed it in my XSLT:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="lookup" select="document('documentFile')"/>

<xsl:template match="/">
  Do the processing how you want to
</xsl:template>
</xsl:stylesheet>

Since you do not want to use the document() function in your XSLT, you could merge your input files using DOM functions in Java.

DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document merge = db.newDocument();
Element root = merge.createElement("root");
merge.appendChild(root);
Document d1 = db.parse(new File("file1.xml"));
Document d2 = db.parse(new File("file2.xml"));
root.appendChild(merge.importNode(d1.getDocumentElement(), true));
root.appendChild(merge.importNode(d2.getDocumentElement(), true));

The merged document could then be passed to XSLT if needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM