Sort parent nodes XML depends on child nodes values

前端 未结 2 1041
遇见更好的自我
遇见更好的自我 2021-01-20 02:17

I have a following XML

 
  
  
   
     
    
       

        
相关标签:
2条回答
  • 2021-01-20 02:40

    I think you can go with this simple transform:

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

    When applied to your input (corrected to make it well-formed):

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

    produces:

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

    Explanation:

    • Use of identity rule to copy every thing as is.
    • override the required DataN elements and simple application of sort condition based on $field input parameter.
    • data-type for sorting dynamically changes according to element field type
    0 讨论(0)
  • 2021-01-20 02:55

    This transformation implements exactly the stated requirements. It takes special care to preserve the exact order of the elements that are not to be sorted. No other answer at present does this:

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

    When applied on the following XML document (the same as the provided one, but with an additional <Element C=""/> inserted between Data1 and Data2 so that we can verify the preservation of ordering of the non-sorted elements):

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

    produces the wanted, correct result -- note that the position of <Element C=""/> is preserved:

    <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>
    
    0 讨论(0)
提交回复
热议问题