2

我发现了一些与此类似的问题,但努力将解决方案“弯曲”到我需要的解决方案,所以再次提问表示歉意。

我有一些这样的 XML:

<?xml version="1.0" encoding="UTF-8"?>

<ns:Root
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ns="urn:Test.Namespace"  
    xsi:schemaLocation="urn:Test.Namespace Test1.xsd"
    >
    <ns:element1 id="001">
        <ns:element2 id="001.1" order="1">
            <ns:element3 id="001.1.1" />
        </ns:element2>
        <ns:element2 id="001.2" order="2">
            <ns:element3 id="001.1.2" />
        </ns:element2>        
    </ns:element1>
    <ns:element1 id="003">
        <ns:element2 id="007.0" order="1">
            <ns:element3 id="007.1.1" />
        </ns:element2>
    </ns:element1>
    <ns:element1 id="002">
        <ns:element2 id="002.1" order="3">
            <ns:element3 id="002.1.1" />
        </ns:element2>
        <ns:element2 id="002.2" order="4">
            <ns:element3 id="002.1.2" />
        </ns:element2> 
    </ns:element1>    
</ns:Root>

我写了这个 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ns="urn:Test.Namespace"
                >
    <xsl:output indent="no" />
    <xsl:template match="text()[not(string-length(normalize-space()))]"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates>
            <xsl:sort select="/ns:Root/ns:element1/@id" />
            <xsl:copy-of select="." />
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ns:element1">
        <xsl:copy-of select="." />
        <xsl:apply-templates />        
    </xsl:template>

    <xsl:template match="ns:element2">
        <xsl:copy-of select="." />
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="ns:element3">
        <xsl:copy-of select="." />
    </xsl:template>

</xsl:stylesheet>

(我从这里抄写了这个大纲如何对 xml 进行排序?

我想要做的是使用这个 XSLT 按id属性对我的原始 XML 进行排序element1并生成 XML。这个想法是,一旦它被排序,我可以用其他一些 XSLT 处理它以获得最终结果。

不幸的是,这并没有给我任何输出,这让我觉得某处有一个非常愚蠢的错字,但我看不到它。

4

2 回答 2

4

你的问题都出在这个匹配的模板上

<xsl:template match="/">
    <xsl:apply-templates>
        <xsl:sort select="/ns:Root/ns:element1/@id" />
        <xsl:copy-of select="." />
    </xsl:apply-templates>
</xsl:template>

首先,\符号匹配文档级元素,它与根ns:Root不同,而是一个级别。这意味着当您执行<xsl:apply-templates>所有操作时,将选择ns:root元素,其中只有一个,因此没有必要对其进行排序!

您可能需要开始的是像这样匹配根元素,复制它,然后开始对子元素进行排序。

<xsl:template match="/*">
    <xsl:copy>
        <!-- Code to select and sort childrens -->
    </xsl:copy>
</xsl:template>

您遇到的下一个问题是 sort 语句。您正在使用 xpath 表达式/ns:Root/ns:element1/@id,但这是绝对路径,而不是相对路径,因此只会获取文档中第一个ns:element1的 @id 属性。

假设您已经定位在根元素上,并假设它只有ns:element1元素作为子元素,您可以这样做

    <xsl:apply-templates>
        <xsl:sort select="@id" />
    </xsl:apply-templates>

您遇到的最后一个问题是您的xsl:apply-templates中有一个不允许的<xsl:copy-of select="." />语句。您可能应该在此处使用xsl:copy,如上所示。

还值得指出的是,如果您还没有意识到,最好使用 XSLT标识转换来复制现有元素,除非您想以某种方式更改它们。这样您就不必为每种特定类型的元素创建模板。

尝试以下 XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ns="urn:TestNamespace"                >
    <xsl:output indent="yes" />

    <xsl:strip-space elements="*"/>

    <xsl:template match="text()[not(string-length(normalize-space()))]"/>

    <xsl:template match="/*">
        <xsl:copy>
        <xsl:apply-templates select="@*" />
        <xsl:apply-templates>
            <xsl:sort select="@id" />
        </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

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

当应用于您的 XML 时,将输出以下内容

<ns:Root xmlns:ns="urn:Test.Namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="urn:Test.Namespace Test1.xsd">
   <ns:element1 id="001">
      <ns:element2 id="001.1" order="1">
         <ns:element3 id="001.1.1"/>
      </ns:element2>
      <ns:element2 id="001.2" order="2">
         <ns:element3 id="001.1.2"/>
      </ns:element2>
   </ns:element1>
   <ns:element1 id="002">
      <ns:element2 id="002.1" order="3">
         <ns:element3 id="002.1.1"/>
      </ns:element2>
      <ns:element2 id="002.2" order="4">
         <ns:element3 id="002.1.2"/>
      </ns:element2>
   </ns:element1>
   <ns:element1 id="003">
      <ns:element2 id="007.0" order="1">
         <ns:element3 id="007.1.1"/>
      </ns:element2>
   </ns:element1>
</ns:Root>
于 2013-04-30T16:52:17.377 回答
0

是的,这是一个简单的错字。只需将 XSLT 中的名称空间更改为您在 XML 中使用的名称空间。-或相反亦然。

xmlns:ns="urn:Test.Namespace" -> xmlns:ns="urn:TestNamespace"

第二个修复(基于您的评论)仅包括交换。

<xsl:template match="/">
    <xsl:apply-templates>
        <xsl:sort select="/ns:Root/ns:element1/@id" />
        <xsl:copy-of select="." />
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="/">
    <xsl:apply-templates select="ns:Root/ns:element1">
        <xsl:sort select="@id" />
    </xsl:apply-templates>
</xsl:template>
于 2013-04-30T14:53:56.683 回答