Сортировка родительских узлов XML зависит от значений дочерних узлов - PullRequest
3 голосов
/ 12 сентября 2011

У меня есть следующий 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> 

Также я должен отправить имя поля сортировки в качестве параметра ...

Ответы [ 2 ]

2 голосов
/ 12 сентября 2011

Это преобразование точно соответствует заявленным требованиям. Особое внимание уделяется сохранению точного порядка элементов, которые не нужно сортировать. Никакой другой ответ в настоящее время не делает это :

<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>
0 голосов
/ 12 сентября 2011

Я думаю, что вы можете пойти с этим простым преобразованием:

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

Объяснение:

  • Использование правила идентификации для копирования каждой вещи как есть.
  • переопределяет необходимые элементы DataN ипростое применение условия сортировки на основе входного параметра $ field .
  • тип данных для сортировки динамически изменяется в соответствии с типом поля элемента
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...