3

私は次のようなXML構造を持っています:

<root>
    <element>
        <name>Foo</name>
        <subelement>
             <key>1.1</key>
             <value>Lorem ipsum</value>
        </subelement>
        <subelement>
             <key>1.2</key>
             <value>Lorem ipsum dolor</value>
        </subelement>
    </element>
    <element>
        <name>Bar</name>
        <subelement>
             <key>7.3.4</key>
             <value>Seven three four</value>
        </subelement>
        <subelement>
             <key>7.3.8</key>
             <value>Seven three eight</value>
        </subelement>
        <subelement>
             <key>7.1</key>
             <value>Seven one</value>
        </subelement>
    </element>
</root>

私が達成しようとしている<subelement>のは、「最も高い」キーを持つものを除くすべての s を削除することです。特定の 内<key>の のを比較する方法が見つからないようです。<subelements><element>

結果の XML は次のようになります。

<root>
    <element>
        <name>Foo</name>
        <subelement>
             <key>1.2</key>
             <value>Lorem ipsum dolor</value>
        </subelement>
    </element>
    <element>
        <name>Bar</name>
        <subelement>
             <key>7.3.8</key>
             <value>Seven three eight</value>
        </subelement>
    </element>
</root>

どんなヒントでも大歓迎です。

4

2 に答える 2

2

この XSLT 2.0 変換は、キー内の任意の数の「キー コンポーネント」と、任意のキー コンポーネントの可能な正の整数値に対して機能します

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match=
 "subelement
   [not(key eq my:max(../subelement/key))
   or
    key = preceding-sibling::subelement/key
   ]"/>

 <xsl:function name="my:max" as="xs:string">
   <xsl:param name="pValues" as="xs:string+"/>

   <xsl:sequence select=
    "if(not(distinct-values($pValues)[2]))
       then $pValues[1]
     else
      for $vMax1 in
             max(for $s in $pValues
                  return
                    xs:integer(substring-before(concat($s,'.'),'.'))
                 ),

          $vcntMax1Values in
             count($pValues[starts-with(., string($vMax1))])

        return
          if($vcntMax1Values eq 1)
            then $pValues[starts-with(., string($vMax1))]
                          [1]
            else
             for $submax in
                     (my:max(for $val in
                                    $pValues[starts-with(., string($vMax1))]
                                                [contains(., '.')],
                                    $subval in substring-after($val, '.')
                                return
                                    $subval
                             )
                      )
                 return
                   concat($vMax1, '.', $submax)

    "/>
 </xsl:function>
</xsl:stylesheet>

この変換が次の XML ドキュメント(より興味深いものにするために拡張された、提供されたもの) に適用されると、次のようになります。

<root>
    <element>
        <name>Foo</name>
        <subelement>
            <key>1.1</key>
            <value>Lorem ipsum</value>
        </subelement>
        <subelement>
            <key>1.2</key>
            <value>Lorem ipsum dolor</value>
        </subelement>
    </element>
    <element>
        <name>Bar</name>
        <subelement>
            <key>7.3.4</key>
            <value>Seven three four</value>
        </subelement>
        <subelement>
            <key>7.3.8</key>
            <value>Seven three eight</value>
        </subelement>
        <subelement>
            <key>7.3.8.1</key>
            <value>Seven three eight one</value>
        </subelement>
        <subelement>
            <key>7.3.8.1</key>
            <value>Seven three eight one</value>
        </subelement>
        <subelement>
            <key>7.1</key>
            <value>Seven one</value>
        </subelement>
        <subelement>
            <key>10.1</key>
            <value>Ten one</value>
        </subelement>
        <subelement>
            <key>10.1</key>
            <value>Ten one</value>
        </subelement>
    </element>
</root>

必要な正しい結果が生成されます。

<root>
   <element>
      <name>Foo</name>
      <subelement>
         <key>1.2</key>
         <value>Lorem ipsum dolor</value>
      </subelement>
   </element>
   <element>
      <name>Bar</name>
      <subelement>
         <key>10.1</key>
         <value>Ten one</value>
      </subelement>
   </element>
</root>

説明:

この一般的なソリューションの核となるのは、my:max()「構造化された値」の空でないシーケンス (構造化された値は、「.」文字で結合された正の整数のシーケンスです) を指定すると、(多くの可能な値のうちの) 1 つを生成する関数です。最大値。

この関数は再帰的です。次のことを行います

  1. 渡された値がすべて同一の場合、最初の値が返されます。

  2. それ以外の場合は、最初のコンポーネントの最大値を見つけます。

  3. 見つかった最大値を持つ最初のコンポーネントを持つ値が 1 つだけの場合は、この値を返します。

  4. それ以外の場合は、最大の最初のコンポーネントを持つすべての値の「テール」の最大値を (再帰的に) 見つけます。

  5. 最後に、最初のコンポーネントの最大値を、前のステップで見つかった「テール」の最大値と結合し、この値を返します。

于 2012-04-05T03:29:04.753 に答える
-1

次のバージョン 2.0 XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="element">
        <xsl:variable name="sorted">
            <xsl:for-each select="subelement">
                <xsl:sort select="key"/>
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:variable name="highest" select="$sorted/subelement[count($sorted/subelement)]/key"/>
        <element>
            <xsl:copy-of select="name"/>
            <xsl:copy-of select="subelement[key=$highest]"/>
        </element>
    </xsl:template>

</xsl:stylesheet>

サンプル入力 XML に適用すると、必要な出力 XML が生成されます。

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <element>
        <name>Foo</name>
        <subelement>
            <key>1.2</key>
            <value>Lorem ipsum dolor</value>
        </subelement>
    </element>
    <element>
        <name>Bar</name>
        <subelement>
            <key>7.3.8</key>
            <value>Seven three eight</value>
        </subelement>
    </element>
</root>
于 2012-04-05T00:33:30.233 に答える