XSLT对xml文档的一部分进行排序

时间:2012-05-04 15:15:21

标签: xslt

我一直在努力解决一个需求,我需要对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>

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

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

换句话说,我想基于父/值对子树GrandFather进行排序。休息一切都应该保持不变。我尝试过类似下面的内容..但这只是将源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>

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分:0)

问题是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,并在每个输入元素处查看样式表以确定要输出的内容。