TransformerFactory结合FOP:禁用ACCESS_EXTERNAL_DTD后的大小写匹配问题
问题描述
我正在为一段用FOP库生成PDF文件的代码做XXE防护。原代码基于xalan-2.7.2的org.apache.xalan.processor.TransformerFactoryImpl实现,运行正常:
protected static void transformTo(Result result, Source src, String mimeFormat, String sFileNameXsl) throws FOPException { try { TransformerFactory factory = TransformerFactory.newInstance(); File myXslFile = new File(sFileNameXsl); StreamSource xsltSource = new StreamSource(myXslFile); Transformer transformer = factory.newTransformer(xsltSource); transformer.setParameter("fop-output-format", mimeFormat); transformer.transform(src, result); } catch (Exception e) { throw new FOPException(e); } }
因为原实现不支持accessExternalDTD属性,我切换到JDK8的com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl来禁用外部DTD和样式表:
TransformerFactory factory = TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", ClassLoader.getSystemClassLoader()); factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
属性能正常设置,但运行时出现错误:
FATAL ERROR: Cannot convert data type 'int' in 'node-set'.
排查后发现错误源于XSL中错误使用|操作符匹配大小写不同的元素,例如:
<xsl:variable name="numcolumns" select="count(./html:tr/*)|count(./html:TR/*)"/> <xsl:if test="ancestor::html:table[1]/@rules = 'cols'|ancestor::html:TABLE[1]/@rules = 'cols'">
移除大写匹配后代码能正常运行,但我需要同时匹配大小写的元素,该怎么实现?
解决方案
问题出在对XSLT中|操作符的误用:|是节点集并集操作符,只能用于节点集之间,不能直接用于数值(比如count的返回值)或布尔值(比如test里的条件表达式)。针对你的场景,应该这样修改:
- 处理count统计场景
将两个节点集合并后再统计数量,而非分别统计后用|连接:
<xsl:variable name="numcolumns" select="count(./html:tr/* | ./html:TR/*)"/>
这里./html:tr/* | ./html:TR/*会合并所有小写tr和大写TR下的子节点,再统一统计总数。
- 处理xsl:if条件判断场景
布尔值之间的逻辑或需要用or操作符,而非节点集并集的|:
<xsl:if test="ancestor::html:table[1]/@rules = 'cols' or ancestor::html:TABLE[1]/@rules = 'cols'">
因为ancestor::html:table[1]/@rules = 'cols'返回的是布尔值,必须用or完成逻辑或判断。
修改后既能保留大小写元素的匹配逻辑,又能兼容JDK内置的Xalan实现,同时完成XXE防护配置。
内容的提问来源于stack exchange,提问作者Nicolas Baumann
相关产品推荐
相关产品推荐

