Выберите узлы с помощью key () на основе условия


У меня есть ситуация, когда мне нужно выбрать узлы, основанные на определенных условиях, а затем применить группировку Мюнха, чтобы получить уникальные значения. Я нахожусь на XSLT 1.0

<Parent>
    <Child>
        <A></A>
        <B></B>
        <C></C>
    </Child>
    <Child>
        <A></A>
        <B></B>
        <C></C>
    </Child>
    <Child>
        <A></A>
        <B></B>
        <C></C>
    </Child>
</Parent>

Условие, которое я имею для атрибута use, является: Если не пусто, в противном случае использовать использовать А. Б.

Я придумал решение, которое будет работать для фиксированных значений ширины для узлов A и B. Поэтому, если A и B имеют длину n, я могу сделать что-то вроде этого:

<xsl:key name="groupKey" match="/Parent/Child" use="substring(concat(A,B),1,n)">

Итак, если A нет, я могу использовать B. Но у меня нет удалось выяснить, как использовать string-length() для получения выражения переменной длины для A и B. Есть идеи?

3 2

3 ответа:

Если вы хотите использовать функцию concat():

use="concat(A, B[not(string(../A)])"

И если под blank вы подразумеваете пустой или только пробел, то используйте:

use="concat(A, B[not(normalize-space(../A)])"

Наконец, если вы действительно хотите использовать и concat(), и substring() (и это действительно сложно, поэтому я не рекомендую его):

concat(substring(A, 1 div string(A) or 0),
       substring(B, 1 div not(string(A)))
      )

Вот полный пример для последнего случая , показывающий, что возвращает вызов concat():

XML документ :

<t>
    <p>
        <A>xxx</A>
        <B>yyy</B>
    </p>
    <p>
        <A/>
        <B>zzz</B>
    </p>
</t>

Преобразование (просто выводит результаты вычисленных выражений):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

  <xsl:template match="p">
    <xsl:value-of select=
    "concat(substring(A, 1 div string(A) or 0),
            substring(B, 1 div not(string(A)))
            )"/>
  </xsl:template>
</xsl:stylesheet>

Желаемый (правильный) результат:

xxx
zzz

Как насчет:

use="A | B[not(string(../A))]"

Вот еще один вариант, который использует другой use.

Example...

XML Input

<Parent>
    <Child>
        <A>both</A>
        <B>both</B>
        <C>c</C>
    </Child>
    <Child>
        <A>a</A>
        <B></B>
        <C>c</C>
    </Child>
    <Child>
        <A></A>
        <B>b</B>
        <C>c</C>
    </Child>
</Parent>

XSLT 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:key name="child" match="Child" use="(A[string()]|B[string()])[1]"/>

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

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:for-each select="Child[count(.|key('child',(A[string()]|B[string()])[1])[1])=1]">
        <group key="{(A[string()]|B[string()])[1]}">
          <xsl:apply-templates select="key('child',(A[string()]|B[string()])[1])"/>
        </group>
      </xsl:for-each>        
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Вывод XML

<Parent>
   <group key="both">
      <Child>
         <A>both</A>
         <B>both</B>
         <C>c</C>
      </Child>
   </group>
   <group key="a">
      <Child>
         <A>a</A>
         <B/>
         <C>c</C>
      </Child>
   </group>
   <group key="b">
      <Child>
         <A/>
         <B>b</B>
         <C>c</C>
      </Child>
   </group>
</Parent>