通过XSLT和JavaScript对XML文件进行排序

时间:2014-05-08 09:26:21

标签: javascript xml sorting xslt

我目前正在尝试实现一个函数,通过其中一个节点的属性对XML文件进行排序。

要走的路似乎是使用XSLT来转换XML文件,并通过研究我设法将一个有效的XSLT文件放在一起(在一些在线验证器中验证,输出就像预期的那样)。

获得我想要的结果后,我开始实现JavaScript函数,以便在每次需要时自动执行此操作。最终将使用XML文件中的数据创建图表(amCharts)。要正确生成该图表,必须对数据进行排序。

现在一切似乎都在语法方面有效,但是,XSLTProcessor和/或XMLSerializer似乎在解析/组合XML和XLST文件时遇到了问题。

奇怪的是,Firefox也会抛出错误:组件返回失败代码:0x80600001 [nsIXSLTProcessor.importStylesheet]

Chrome似乎没有此问题。

但这不是主要问题。生成的结果包含一个基本的HTML页面,说明有错误,但没有给出确切的错误描述/位置/解释。

我希望在这里看到排序的XML文件,就像在线XML / XSLT验证器一样,它具有相同的输入XML / XSLT内容。

有没有人对这个问题的根源有所了解?非常感谢任何提示和/或解决方案。

最好的问候,

daZza

修改

在生成的页面上研究“文档末尾的额外内容”错误后更深入(并且在我发布OP时忽略了它),似乎错误是在有多个时触发的XML文件中的根元素,显然是错误的。

但是,源XML文件没有多个根节点,并且完全有效。

这让我相信源文件的XSLT重新排序/排序没有按预期完成,尽管它在XSLT验证器中看起来很好。 我想它会以某种方式生成多个根节点,而不是只重新排序根节点中的项节点?

不幸的是,我不是XSLT的专家,所以如果有更详细知识的人可以特别关注XSLT代码,那就太棒了。

EDIT2

我想我可能通过稍微更改XSLT查询来解决问题。我正在为Chrome和Firefox获得一个正确的输出,但IE仍然会抛出错误(我是否提到我讨厌跨浏览器兼容性?-.-)。

仍然需要进一步测试,但至少它是一个进步。仍然欣赏有关该主题的任何提示。

代码:

XML示例代码段(删除的内容,“”部分填入真实文件中):

<?xml version="1.0" encoding="utf-8"?>
<root>
    <item Art="" LinkTitle="" Eindruck="" Bereich="" Unterbereich="" Priority="" Handlungsma_x00df_nahme="" Status_x0020_der_x0020_Ma_x00df_="" Aufwand="" Benefit="" Termin_x0020_der_x0020_Retrospek="" Produkt="" Release="" />
    <item Art="" LinkTitle="" Eindruck="" Bereich="" Unterbereich="" Priority="" Handlungsma_x00df_nahme="" Status_x0020_der_x0020_Ma_x00df_="" Aufwand="" Benefit="" Termin_x0020_der_x0020_Retrospek="" Produkt="" Release="" />
</root>

XSLT文件

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:choose>
                <xsl:when test="*[local-name()='item']">
                    <xsl:apply-templates select="@* | node()">
                        <xsl:sort select="@Unterbereich" />
                    </xsl:apply-templates>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="@* | node()" />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

JavaScript功能

function sortXML()
{
    var parser = new DOMParser();

    // xml and xsl are correctly filled with the data from their appropriate files 
    // via AJAX GET requests earlier in the code
    var domToBeTransformed = xml;
    var xslt = xsl;
    var processor = new XSLTProcessor();

    processor.importStylesheet(xslt);

    var newDocument = processor.transformToDocument(domToBeTransformed);
    var serializer = new XMLSerializer();
    var newDocumentXml = serializer.serializeToString(newDocument);

    alert(newDocumentXml);
}

当前生成的文档(var newDocumentXml)

<html xmlns="http://www.w3.org/1999/xhtml">
    <body>
        <parsererror style="display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black">
        <h3>This page contains the following errors:</h3>
        <div style="font-family:monospace;font-size:12px">error on line 1 at column 1: Extra content at the end of the document</div>
        <h3>Below is a rendering of the page up to the first error.</h3>
        </parsererror>
    </body>
</html> 

1 个答案:

答案 0 :(得分:0)

首先,我会重新设置您的XSLT以避免使用 xsl:choose 。如果您已经匹配属性或文本节点,则测试子元素是否存在没有意义。使用单独的模板可能更好(更干净,压痕更少)。

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[*[local-name()='item']]">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="node()">
                <xsl:sort select="@Unterbereich" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

首先要注意的是,您在XSLT中指定了版本“2.0”。 Microsoft(以及IE)本身不支持XSLT 2.0。但是,在这种情况下,您没有使用任何XSLT 2.0功能,因此将其更改为XSLT 1.0应该不是问题(当然,如果您的实际XSLT确实需要使用2.0,那么这是一个完全独立的问题!)< / p>

但我认为这不再是你的XSLT的问题,而是更多关于如何在浏览器中使用javascript进行转换的问题。您提供的代码仅适用于Chrome和Firefox(我认为是Opera)。 IE不支持这些命令,并且有自己的方法。而且进一步复杂化,IE10及以上版本的做法与以前的版本不同!

无论如何,我前往Object doesn't support property or method 'transformNode' in Internet Explorer 10 (Windows 8)并找到了一个很好的JavaScript示例。尝试重新编写您的JavaScript:

function sortXML()
{
  if (typeof (XSLTProcessor) != "undefined") 
  {
      var xsltProcessor = new XSLTProcessor();
      xsltProcessor.importStylesheet(xsl);
      var resultDocument = xsltProcessor.transformToDocument(xml);
      var serializer = new XMLSerializer();
      var newDocumentXml = serializer.serializeToString(resultDocument);
      alert(newDocumentXml);
  }
  else if (typeof (xml.transformNode) != "undefined") 
  {
      var ex = xml.transformNode(xsl);
      alert(ex);
  }
  else
  {
     var xslDoc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument");
     xslDoc.load(xsl);

     var xslt = new ActiveXObject("Msxml2.XSLTemplate");
     xslt.stylesheet = xslDoc;

     var xslProc = xslt.createProcessor();
     xslProc.input = xml;
     xslProc.transform();

     alert(xslProc.output);
  }
}