排序父节点XML取决于子节点值

时间:2011-09-12 07:12:15

标签: xml xslt sorting xpath parameters

我有以下XML

<Root> 
  <Element A/>
  <Element B/>
  <Data1> 
    <DataElement/> 
    <Values>
       <Value>2222</Value> 
       <Name>field1</Name>
    </Values> 
    <Values>
       <Value>ABC</Value> 
       <Name>field2</Name>
    </Values> 
  </Data1> 
  <Data2> 
    <DataElement/> 
    <Values>
       <Value>1111</Value> 
       <Name>field1</Name>
    </Values> 
    <Values>
       <Value>XYZ</Value> 
       <Name>field2</Name>
    </Values> 
  </Data2>
  <DataN> 
    ... 
  </DataN> 
</Root> 

我需要获取与指定字段名称的“值”排序的数据部分相同的XML,例如: 按“field1”排序将返回

    <Root> 
  <Element A/>
  <Element B/>
  <Data2> 
    <DataElement/> 
    <Values>
       <Value>1111</Value> 
       <Name>field1</Name>
    </Values> 
    <Values>
       <Value>XYZ</Value> 
       <Name>field2</Name>
    </Values> 
  </Data2>
  <Data1> 
    <DataElement/> 
    <Values>
       <Value>2222</Value> 
       <Name>field1</Name>
    </Values> 
    <Values>
       <Value>ABC</Value> 
       <Name>field2</Name>
    </Values> 
  </Data1>   
  <DataN> 
    ... 
  </DataN> 
</Root> 

另外,我必须将sort字段的名称作为参数...

发送

2 个答案:

答案 0 :(得分:2)

此转换完全符合规定的要求。需要特别注意保留不要排序的元素的确切顺序。目前没有其他答案

<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:param name="vField" select="'field1'"/>
 <xsl:param name="pSortType" select="'number'"/>

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

   <xsl:template match="*[starts-with(name(),'Data')]">
    <xsl:variable name="vPos" select=
      "count(preceding-sibling::*[starts-with(name(),'Data')])+1"/>

  <xsl:for-each select="/*/*[starts-with(name(),'Data')]">
   <xsl:sort select="Values[Name=$vField]/Value"
             data-type="{$pSortType}"/>
   <xsl:if test="position() = $vPos">
    <xsl:copy-of select="."/>
   </xsl:if>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

应用于以下XML文档(与提供的文档相同,但在<Element C=""/>Data1之间插入了额外的Data2,以便我们可以验证保存未排序元素的排序):

<Root>
    <Element A=""/>
    <Element B=""/>
    <Data1>
        <DataElement/>
        <Values>
            <Value>2222</Value>
            <Name>field1</Name>
        </Values>
        <Values>
            <Value>ABC</Value>
            <Name>field2</Name>
        </Values>
    </Data1>
        <Element C=""/>
    <Data2>
        <DataElement/>
        <Values>
            <Value>1111</Value>
            <Name>field1</Name>
        </Values>
        <Values>
            <Value>XYZ</Value>
            <Name>field2</Name>
        </Values>
    </Data2>
</Root>

生成想要的正确结果 - 请注意保留<Element C=""/>的位置

<Root>
   <Element A=""/>
   <Element B=""/>
   <Data2>
      <DataElement/>
      <Values>
         <Value>1111</Value>
         <Name>field1</Name>
      </Values>
      <Values>
         <Value>XYZ</Value>
         <Name>field2</Name>
      </Values>
   </Data2>
   <Element C=""/>
   <Data1>
      <DataElement/>
      <Values>
         <Value>2222</Value>
         <Name>field1</Name>
      </Values>
      <Values>
         <Value>ABC</Value>
         <Name>field2</Name>
      </Values>
   </Data1>
</Root>

答案 1 :(得分:0)

我认为你可以采用这种简单的转换:

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

    <xsl:param name="field" select="'field1'"/>

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

    <xsl:template match="Root">
        <xsl:copy>
            <xsl:apply-templates select="@*|*">
                <xsl:sort select="Values[Name=$field]/
                    Value[string(number(.))!='NaN']" 
                    data-type="number"/>
                <xsl:sort select="Values[Name=$field]/
                    Value[string(number(.))='NaN']"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

当应用于您的输入时(已更正以使其格式正确):

<Root> 
    <Element A=""/>
    <Element B=""/>
    <Data1> 
        <DataElement/> 
        <Values>
            <Value>2222</Value> 
            <Name>field1</Name>
        </Values> 
        <Values>
            <Value>ABC</Value> 
            <Name>field2</Name>
        </Values> 
    </Data1> 
    <Data2> 
        <DataElement/> 
        <Values>
            <Value>1111</Value> 
            <Name>field1</Name>
        </Values> 
        <Values>
            <Value>XYZ</Value> 
            <Name>field2</Name>
        </Values> 
    </Data2> 
</Root>

产生

<Root>
    <Element A=""></Element>
    <Element B=""></Element>
    <Data2>
        <DataElement></DataElement>
        <Values>
            <Value>1111</Value>
            <Name>field1</Name>
        </Values>
        <Values>
            <Value>XYZ</Value>
            <Name>field2</Name>
        </Values>
    </Data2>
    <Data1>
        <DataElement></DataElement>
        <Values>
            <Value>2222</Value>
            <Name>field1</Name>
        </Values>
        <Values>
            <Value>ABC</Value>
            <Name>field2</Name>
        </Values>
    </Data1>
</Root>

说明:

  • 使用身份规则按原样复制所有内容。
  • 根据 $ field 输入参数覆盖所需的 DataN 元素和排序条件的简单应用。
  • 用于排序的数据类型根据元素字段类型动态更改