简体   繁体   English

使用XSLT转换XML时的ArrayIndexOutOfBoundsException

[英]ArrayIndexOutOfBoundsException when transforming XML using XSLT

I am using the Java javax.xml.transform library in my Scala Play application to perform a simple XSLT transformation on some XML. 我在Scala Play应用程序中使用Java javax.xml.transform库对某些XML执行简单的XSLT转换。 I am trying to remove the namespace from one of the elements, but I am getting an exception when I POST XML to the endpoint which does the transformation. 我试图从其中一个元素中删除命名空间,但是当我将XML发送到执行转换的端点时,我遇到了异常。

The method I have written to do the transformation is below: 我编写的用于转换的方法如下:

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
  }
}

Through putting println s in my code, I have deduced that it is in fact failing at the xformer.transform(input, output) line. 通过将println放入我的代码中,我推断它实际上在xformer.transform(input, output)行中失败了。 The XML I am passing in and the XSL file I am using to transform are below: 我传入的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>

My expected output is this: 我的预期输出是这样的:

<?xml version="1.0"?>
    <Message>
        <EnvelopeVersion>2.0</EnvelopeVersion>
        <Header>
            <MessageDetails>
                ...
                ...
                ...
            </MessageDetails>
            <SenderDetails/>
        </Header>
        <OtherDetails>
            <Keys/>
        </OtherDetails>
        <Body>
        </Body>
    </Message>

The error I get back from sending a POST request to my endpoint is this: 从发送POST请求到我的端点的错误是:

{
    "statusCode": 500,
    "message": "javax.xml.transform.TransformerException: java.lang.ArrayIndexOutOfBoundsException: -1"
}

I do not have much experience with XSLT and have inherited this code from someone else to try to debug, so if anyone with XML/XSLT experience could give me some help I would greatly appreciate it. 我没有太多的XSLT经验,并且从其他人那里继承了这个代码来尝试调试,所以如果有XML / XSLT经验的人能给我一些帮助,我会非常感激。 The perplexing thing is that the person I got this problem from had written Unit Tests using this method (send in my example XML and get out the expected XML) and they passed so I don't know where to look next. 令人困惑的是,我遇到这个问题的人已经使用这种方法编写了单元测试(发送我的示例XML并获得预期的XML)并且他们通过了所以我不知道接下来要去哪里看。

Right so after a few hours of debugging and fretting over this, I found the solution! 正好经过几个小时的调试和对此的烦恼,我找到了解决方案!

The default transformer which my Play application was using handles XSLT differently, and was getting confused at the line <xsl:param name="ancestralNamespace" select="namespace-uri(/*[1])"/> . 我的Play应用程序使用的默认转换器以不同的方式处理XSLT,并且在<xsl:param name="ancestralNamespace" select="namespace-uri(/*[1])"/>行中感到困惑。 What solved my issue was to use a different transformer. 解决我的问题是使用不同的变压器。 The one I found to work was Xalan (version 2.7.2), and after importing that into my project build file I hit the endpoint and the transformation was successful. 我发现工作的是Xalan(版本2.7.2),在将其导入我的项目构建文件后,我点击端点并且转换成功。

To import the version I found to work, add the following to your build: 要导入我发现的版本,请在构建中添加以下内容:

"xalan" % "xalan" % "2.7.2" % "runtime"

I believe that the "runtime" section is the most important part, as it seems to overwrite what the application would normally use. 我认为“运行时”部分是最重要的部分,因为它似乎覆盖了应用程序通常使用的内容。 I would guess that the reason my tests passed but my endpoint failed is that Scala Test runs with different configuration to runtime. 我猜测我的测试通过但我的端点失败的原因是Scala Test以不同的配置运行到运行时。 Nothing else about my code had to be changed. 我的代码没有别的东西可以改变。

I hope this helps to stop anyone else from encountering this (admittedly rather unique) error! 我希望这有助于阻止其他人遇到这个(诚然相当独特)的错误! I ended up trawling through countless forums from as far back as 2002 before resorting to trying a different runtime configuration. 我最终在2002年之前在无数的论坛上拖网,然后尝试了不同的运行时配置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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