2011-09-12 113 views
3

我有下面的XML排序父節點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> 

我需要與「值」指定的字段名的,對於exmple排序的數據部分相同的XML: 排序「字段1」將返回

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

另外,我要送排序字段作爲參數的名稱...

+0

提供的XML格式不正確。 –

+0

好問題,+1。保留'Data'X元素和所有其他元素的相對順序是有一點難度的,但這絕對是可能的。 –

回答

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> 

說明:

  • 使用身份規則複製ev就是這樣。
  • 覆蓋所需的DataN元素和基於$ field輸入參數的排序條件的簡單應用。
  • 數據類型進行排序,根據元素的字段類型
+0

這個轉換根本不會產生所需的輸出! -1。 –

+0

@Dimitre,對不起,不便之處。我現在執行了正確的測試併爲我的解決方案提供了一個修復程序。該方法仍然是一樣的。 –

+0

@_empo:我明白了。在我的答案中嘗試使用XML文檔解決問題,並查看是否保留了元素排序(提示:不是)。 –

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文檔(同爲所提供的一個應用,但與Data1Data2這樣我們就可以驗證保護之間插入一個額外的<Element C=""/>非排序元素的順序)的:

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