Java 中带有参数的高效 XSLT 管道
这个问题的最佳答案描述了一种在 Java 中实现高效 XSLT 管道的技术:
不幸的是,虽然 Transformer 似乎公开了用于设置 XSLT 参数的 API,但这似乎没有任何效果。例如,我有以下代码:
Transformer.java
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.Templates;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.Transformer;
import java.io.File;
public class MyTransformer {
public static void main(String[] args) throws javax.xml.transform.TransformerConfigurationException, javax.xml.transform.TransformerException{
SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();
// These templates objects could be reused and obtained from elsewhere.
Templates templates1 = stf.newTemplates(new StreamSource( new File("MyStylesheet1.xslt")));
Templates templates2 = stf.newTemplates(new StreamSource(new File("MyStylesheet2.xslt")));
TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);
th1.setResult(new SAXResult(th2));
th2.setResult(new StreamResult(System.out));
Transformer t = stf.newTransformer();
//SETTING PARAMETERS HERE
t.setParameter("foo","this is from param 1");
t.setParameter("bar","this is from param 2");
t.transform(new StreamSource(new File("in.xml")), new SAXResult(th1));
// th1 feeds th2, which in turn feeds System.out.
}
}
MyStylesheet1.xslt
<?xml version="1.0"?>
<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:foo="urn:foo" version="1.0">
<output method="xml"/>
<param name="foo"/>
<template match="@*|node()">
<copy>
<apply-templates select="@*|node()"/>
</copy>
</template>
<template match="foo:my/foo:hello">
<copy>
<foo:world>
foo is : <value-of select="$foo"/>
</foo:world>
</copy>
</template>
</stylesheet>
MyStylesheet2.xslt
<?xml version="1.0"?>
<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:foo="urn:foo" version="1.0">
<output method="xml"/>
<param name="bar"/>
<template match="@*|node()">
<copy>
<apply-templates select="@*|node()"/>
</copy>
</template>
<template match="foo:my/foo:hello/foo:world">
<copy>
<apply-templates select="@*|node()"/>
<attribute name="attr">
<value-of select="$bar"/>
</attribute>
</copy>
</template>
</stylesheet>
in.xml
<my xmlns="urn:foo">
<hello/>
</my>
这给出了以下输出:
<?xml version="1.0" encoding="UTF-8"?><my xmlns="urn:foo">
<hello><foo:world xmlns:foo="urn:foo">foo is : </foo:world></hello>
</my>
如您所见 foo:world/@attr 为空,并且 foo:world 的文本内容显示“foo 是:”。预期的行为是它们应该使用传递到 setParameter 方法的参数进行填充。
有没有办法使用此技术设置 XSL 转换参数。如果没有,有人可以推荐一种替代技术来在 Java 中有效地转换样式表,这样也可以设置 XSLT 参数吗?
The top answer to this question describes a technique to implement an efficient XSLT pipeline in Java:
Efficient XSLT pipeline in Java (or redirecting Results to Sources)
Unfortunately, while Transformer seems to expose an API for setting XSLT parameters, this does not seem to have any effect. For example, I have the following code:
Transformer.java
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.Templates;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.Transformer;
import java.io.File;
public class MyTransformer {
public static void main(String[] args) throws javax.xml.transform.TransformerConfigurationException, javax.xml.transform.TransformerException{
SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();
// These templates objects could be reused and obtained from elsewhere.
Templates templates1 = stf.newTemplates(new StreamSource( new File("MyStylesheet1.xslt")));
Templates templates2 = stf.newTemplates(new StreamSource(new File("MyStylesheet2.xslt")));
TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);
th1.setResult(new SAXResult(th2));
th2.setResult(new StreamResult(System.out));
Transformer t = stf.newTransformer();
//SETTING PARAMETERS HERE
t.setParameter("foo","this is from param 1");
t.setParameter("bar","this is from param 2");
t.transform(new StreamSource(new File("in.xml")), new SAXResult(th1));
// th1 feeds th2, which in turn feeds System.out.
}
}
MyStylesheet1.xslt
<?xml version="1.0"?>
<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:foo="urn:foo" version="1.0">
<output method="xml"/>
<param name="foo"/>
<template match="@*|node()">
<copy>
<apply-templates select="@*|node()"/>
</copy>
</template>
<template match="foo:my/foo:hello">
<copy>
<foo:world>
foo is : <value-of select="$foo"/>
</foo:world>
</copy>
</template>
</stylesheet>
MyStylesheet2.xslt
<?xml version="1.0"?>
<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:foo="urn:foo" version="1.0">
<output method="xml"/>
<param name="bar"/>
<template match="@*|node()">
<copy>
<apply-templates select="@*|node()"/>
</copy>
</template>
<template match="foo:my/foo:hello/foo:world">
<copy>
<apply-templates select="@*|node()"/>
<attribute name="attr">
<value-of select="$bar"/>
</attribute>
</copy>
</template>
</stylesheet>
in.xml
<my xmlns="urn:foo">
<hello/>
</my>
Which gives me the following output:
<?xml version="1.0" encoding="UTF-8"?><my xmlns="urn:foo">
<hello><foo:world xmlns:foo="urn:foo">foo is : </foo:world></hello>
</my>
As you can see foo:world/@attr is empty, and the text contents of foo:world says "foo is:". The expected behaviour is that they should have been populated with the parameters passed into the setParameter method.
Is there a way to set XSL transformation parameters using this technique. If not, could anyone recommend an alternative technique for transforming stylesheets efficiently in Java, such that XSLT parameters may also be set?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题是每个 TransformerHandler 都有一个与之关联的单独的 Transformer。您的第二个模板有问题,但由于这是一个示例,我想这并不重要。您想要:
请注意,您也不需要创建第三个变压器,您只需在 th1.getTransformer() 上启动变换链即可
The problem is that each TransformerHandler has a separate Transformer associated with it. There's a problem with your 2nd template, but as this is an example I guess that doesn't matter. You want:
Note that you also don't need to create a 3rd transformer you can just start the transform chain on th1.getTransformer()
与最后一个注释相关。
在 th1.getTransformer() 上调用 Transform() 且结果再次指向 th1 是不正确的。它将被处理两次。
使用 new Transformer() (如初始帖子中所示)是正确的方法。
related to the last note.
invoking transform() on th1.getTransformer() with the result pointing again on th1 is not correct. It will be processed twice.
using new Transformer() like shown in the initial post is the correct way.