【问题标题】:XSLT sorting a part of xml documentXSLT 对 xml 文档的一部分进行排序
【发布时间】:2012-05-07 16:13:39
【问题描述】:

我一直在处理需要对 xml 文档的一部分(而不是完整的树)进行排序的需求。

<Root>
<AllData>
    <Data_not_to_be_sorted>
        <Additional_data1>
            <Some_test_data1/>
            <Some_test_data2/>
        </Additional_data1>
    </Data_not_to_be_sorted>
    <RealData>
        <Some_data1/>
        <Some_data2/>
        <GrandFather>
            <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>4</Value>
                <Name>name in 4</Name>
            </Father>
        </GrandFather>
        <GrandFather>
        <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>3</Value>
                <Name>name in 3</Name>
            </Father>
        </GrandFather>
    </RealData>
            <RealData>
        <Some_data1/>
        <Some_data2/>
        <GrandFather>
            <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>2</Value>
                <Name>name in 2</Name>
            </Father>
        </GrandFather>
        <GrandFather>
        <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>1</Value>
                <Name>name in 1</Name>
            </Father>
        </GrandFather>
    </RealData>

</AllData>
</Root>

所以在对父亲/值进行排序后,我应该得到正确的祖父序列

<Root>
<AllData>
    <Data_not_to_be_sorted>
        <Additional_data1>
            <Some_test_data1/>
            <Some_test_data2/>
        </Additional_data1>
    </Data_not_to_be_sorted>
    <RealData>
        <Some_data1/>
        <Some_data2/>
        <GrandFather>
            <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>3</Value>
                <Name>name in 3</Name>
            </Father>
        </GrandFather>
        <GrandFather>
        <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>4</Value>
                <Name>name in 4</Name>
            </Father>
        </GrandFather>
    </RealData>
            <RealData>
        <Some_data1/>
        <Some_data2/>
        <GrandFather>
            <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>1</Value>
                <Name>name in 1</Name>
            </Father>
        </GrandFather>
        <GrandFather>
        <Data_required_as_it_is></Data_required_as_it_is>
            <Father>
                <Value>2</Value>
                <Name>name in 2</Name>
            </Father>
        </GrandFather>
    </RealData>

</AllData>
</Root>

换句话说,我想根据父/值对子树祖父进行排序。休息一切都应该保持不变。我已经尝试过类似下面的东西..但这只是将源 xml 复制到输出中。

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Template to copy the nodes as they are -->

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


<xsl:template match="GrandFather">
<xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates select="node()">    
    <xsl:sort select="self::Father/Value" data-type="number"/>
    </xsl:apply-templates>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

【问题讨论】:

  • 一般来说,当你说某事“不工作”时,你需要指定如何:不会编译?在运行时崩溃?出乎意料的结果?
  • 实际上,不工作的意思是,这段代码给了我原来的输出......所以我得到的输出与源代码相同。

标签: xslt


【解决方案1】:

这个正确、更短、更简单、更通用的转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="*[F]">
  <xsl:copy>
   <xsl:apply-templates select="@*"/>

   <xsl:apply-templates select="node()">
    <xsl:sort select="self::F/Value" data-type="number"/>
   </xsl:apply-templates>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<Root>
    <AllData>
        <Data_not_to_be_sorted>
            <Additional_data1>
                <Some_test_data1/>
                <Some_test_data2/>
            </Additional_data1>
        </Data_not_to_be_sorted>
        <data>
            <Some_data1></Some_data1>
            <Some_data2></Some_data2>
            <F>
                <Value>2</Value>
                <Name>name in 2</Name>
            </F>
            <F>
                <Value>1</Value>
                <Name>name in 1</Name>
            </F>
        </data>
        <data>
            <Some_data1></Some_data1>
            <Some_data2></Some_data2>
            <F>
                <Value>4</Value>
                <Name>name 4</Name>
            </F>
            <F>
                <Value>3</Value>
                <Name>name in 3</Name>
            </F>
        </data>
    </AllData>
</Root>

产生想要的正确结果:

<Root>
   <AllData>
      <Data_not_to_be_sorted>
         <Additional_data1>
            <Some_test_data1/>
            <Some_test_data2/>
         </Additional_data1>
      </Data_not_to_be_sorted>
      <data>
         <Some_data1/>
         <Some_data2/>
         <F>
            <Value>1</Value>
            <Name>name in 1</Name>
         </F>
         <F>
            <Value>2</Value>
            <Name>name in 2</Name>
         </F>
      </data>
      <data>
         <Some_data1/>
         <Some_data2/>
         <F>
            <Value>3</Value>
            <Name>name in 3</Name>
         </F>
         <F>
            <Value>4</Value>
            <Name>name 4</Name>
         </F>
      </data>
   </AllData>
</Root>

【讨论】:

  • 嗨 Dimitre,感谢您的解决方案 :) ..但是我的要求有所改变..现在我需要根据孙子值对 GrandFather 进行排序..我正在重新发布问题..
  • Dimitre,我看过之前的帖子,您在其中发布了解决方案。我的要求与此类似,我能够根据该帖子编写代码。感谢您之前的帖子:)。我指的链接是-stackoverflow.com/questions/616387/…
  • 所以我从中学到的东西是 - 每当我们想要对特定段进行排序时,首先将模式与其父级匹配,然后将排序模板应用于子级...感谢所有参与的人回复了我的疑问。
  • @user1375199:很高兴我的回答解决了您的问题。请您接受这个答案——点击答案旁边的复选标记吗?
  • Dimitre,我接受了你的回答。谢谢...一个查询..我正在使用以下代码来满足我的要求 -
【解决方案2】:

问题是F/Value 不是Root 的孩子。此外,在Root 下应用排序(如果您提供了可用的排序键)将仅对根的子元素进行排序。你需要做这样的事情(未经测试):

<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="data">
    <xsl:apply-templates select="Some_data1"/>
    <xsl:apply-templates select="Some_data2"/>
    <xsl:apply-templates select="F">
        <xsl:sort select="Value"/>
    </xsl:apply-templates>
</xsl:template>

关键是要记住样式表是声明性的,而不是程序性的。 XSLT 引擎读取您的 XML,并在每个输入元素处查看样式表以决定输出什么。

【讨论】:

  • 非常感谢,您的回答帮助我编写了正确的代码...这是满足此要求的代码...
  • 我唯一需要做的就是在您的代码中添加 标记以使代码正常工作...非常感谢 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 2018-03-24
  • 2020-09-11
  • 2013-03-07
相关资源
最近更新 更多