我在Scala Play应用程序中使用Java javax.xml.transform
库对某些XML执行简单的XSLT转换。我试图从其中一个元素中删除命名空间,但是当我将XML发送到执行转换的端点时,我遇到了异常。
我编写的转换方法如下:
def transformXml(xml: String, xslName: String): Try[String] = {
Try {
// Create transformer factory
val factory: TransformerFactory = TransformerFactory.newInstance()
// Use the factory to create a template containing the xsl file
val template: Templates = factory.newTemplates(new StreamSource(new FileInputStream(s"app/xsl/$xslName.xsl")))
// Use the template to create a transformer
val xformer: Transformer = template.newTransformer()
// Prepare the input for transformation
val input: Source = new StreamSource(new StringReader(xml))
// Prepare the output for transformation result
val outputBuffer: Writer = new StringWriter
val output: javax.xml.transform.Result = new StreamResult(outputBuffer)
// Apply the xslt transformation to the input and store the result in the output
xformer.transform(input, output)
// Return the transformed XML
outputBuffer.toString
}
}
通过在我的代码中添加println
,我推断它实际上在xformer.transform(input, output)
行失败了。我传入的XML和我用来转换的XSL文件如下:
<?xml version="1.0"?>
<Message xmlns="http://foo.bar" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
...
...
...
</MessageDetails>
<SenderDetails/>
</Header>
<OtherDetails>
<Keys/>
</OtherDetails>
<Body>
</Body>
</Message>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:param name="ancestralNamespace" select="namespace-uri(/*[1])"/>
<xsl:copy>
<xsl:apply-templates select="@*|node()">
<xsl:with-param name="ancestralNamespace" select="$ancestralNamespace"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="*[contains(namespace-uri(),'foo.bar')]">
<xsl:param name="ancestralNamespace" select="namespace-uri(..)"/>
<xsl:element name="{local-name()}" namespace="">
<xsl:apply-templates select="@*|node()">
<xsl:with-param name="ancestralNamespace" select="$ancestralNamespace"/>
</xsl:apply-templates>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
我的预期输出是:
<?xml version="1.0"?>
<Message>
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
...
...
...
</MessageDetails>
<SenderDetails/>
</Header>
<OtherDetails>
<Keys/>
</OtherDetails>
<Body>
</Body>
</Message>
我从发送POST请求到我的端点的错误是:
{
"statusCode": 500,
"message": "javax.xml.transform.TransformerException: java.lang.ArrayIndexOutOfBoundsException: -1"
}
我对XSLT没有多少经验,并且从其他人那里继承了这段代码来尝试调试,所以如果有XML / XSLT经验的人能给我一些帮助,我将非常感激。令人困惑的是,我遇到这个问题的人已经使用这种方法编写了单元测试(发送我的示例XML并获得预期的XML)并且他们通过了所以我不知道接下来要去哪里看。
答案 0 :(得分:2)
正确,经过几个小时的调试和对此的烦恼,我找到了解决方案!
我的Play应用程序使用的默认转换器以不同的方式处理XSLT,并且在<xsl:param name="ancestralNamespace" select="namespace-uri(/*[1])"/>
行感到困惑。解决我的问题是使用不同的变压器。我发现工作的是Xalan(版本2.7.2),在将其导入我的项目构建文件后,我点击端点并且转换成功。
要导入我发现的版本,请将以下内容添加到您的版本中:
"xalan" % "xalan" % "2.7.2" % "runtime"
我相信&#34;运行时&#34; section是最重要的部分,因为它似乎覆盖了应用程序通常使用的内容。我猜测我的测试通过但我的端点失败的原因是Scala Test以不同的配置运行到运行时。我的代码没有别的东西可以改变。
我希望这有助于阻止其他人遇到这个(诚然相当独特)的错误!我最终在2002年之前在无数的论坛上拖网,然后尝试了不同的运行时配置。