通过XSLT和JavaScript排序XML文件

Sorting XML file via XSLT and JavaScript

本文关键字:XML 文件 排序 JavaScript XSLT 通过      更新时间:2023-09-26

我目前正在尝试实现一个函数,按其中一个节点的属性对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>
<<p> JavaScript函数/strong>
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> 

首先,我将重新调整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,那么这是一个完全不同的问题!)

但我不认为这是您的XSLT的问题,但更多的问题是如何在浏览器中使用javascript完成转换。你给的代码将只工作在Chrome和Firefox(和Opera,我认为)。IE不支持这些命令,它有自己的方法。更复杂的是,IE10及以上版本与以前的版本做的事情不同!

无论如何,我前往对象不支持属性或方法'transformNode'在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);
  }
}