TransformerFactory 和 Xalan 依赖冲突

TransformerFactory and Xalan Dependency Conflict

我有以下代码:

javax.xml.transform.TransformerFactory factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
javax.xml.transform.Transformer transformer = factory.newTransformer();

这正常工作。但是,我还需要在我的 pom.xml 中添加 Xalan 作为依赖项,当我这样做时,上面的代码现在会抛出一个错误:

java.lang.IllegalArgumentException: Not supported: http://javax.xml.XMLConstants/property/accessExternalDTD

我认为这与 Xalan 的 jar 中有不同的 Transformer 实现有关。如何在不更改上述代码并将 Xalan 作为依赖项的情况下解决此冲突?

从 Xalan 中排除 Xerces 解决了这个问题:

<dependency>
    <groupId>xalan</groupId>
    <artifactId>xalan</artifactId>
    <version>2.7.2</version>
    <exclusions>
        <exclusion>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
        </exclusion>
    </exclusions>
</dependency>

如果您有多个 XSL 处理器和/或不同版本,您必须处理并非每个实现都能够处理每个属性的情况。这样做的唯一方法是捕获不支持该属性时抛出的 IllegalArgumentException。看一下 JAXP documentation:

中的这个修改示例
javax.xml.transform.TransformerFactory factory = TransformerFactory.newInstance();

try {
    factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
} catch (IllegalArgumentException e) {
    //jaxp 1.5 feature not supported
}

文档说:

When code change is possible, and for new development, it is recommended that the new properties be set as demonstrated above. By setting the properties this way, applications can be sure to maintain the desired behavior whether they are deployed to older or newer version of the JDK, or whether the properties are set through System Properties or jaxp.properties.

对我有用的解决方案是这样做:

compile('org.opensaml:opensaml:2.6.1') {
    exclude group: 'xerces', module: 'xercesImpl'
    exclude module: 'xalan'
}

它可能来自您项目的其他 xalan 版本。

在您的 POM 中检查 xalan 的依赖层次结构,并在所有 xalan 版本中排除 xercesImpl。

我遇到了一个类似的问题,在 TransformerFactory::newInstance 中创建了 SaxonJ 的实现,在尝试设置它不支持的属性时出现错误。

查看 method documentation,我发现 TransformerFactory 有一个优先级列表,它试图在其中找到 return.

的实现

它查找的第一个位置是在系统属性中,所以在我的 Ant 文件中,在我的 运行 目标中,我添加了以下内容(其他库将具有相同的内容):

<jvmarg value="-Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"/>

这将使 TransformerFactory::newInstance 加载正确的工厂实现。

请记住,我使用的是 OpenJDK8,您必须为其他版本找到正确的包。

需要设置system-level 属性如下

System.setProperty("javax.xml.transform.TransformerFactory","com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");