1

XSLT 2 が推奨されており、これがより簡単になることを願っています。

に似た文書が与えられた場合

<doc xmlns:bob="bob.com">
    <element bob:name="fred" bob:occupation="Dr">Stuff</element>
    <element bob:name="Bill" bob:occupation="Dr" bob:birthMonth="Jan"/>
    <element>Kill Me</element>
    <element bob:name="fred" bob:occupation="Dr">different Stuff</element>
</doc>

bob 名前空間のすべての属性に基づいて、すべての一意の要素を持ちたいと思います。これは代表的なサンプルですが、もっと深い入れ子にするので、ツリーをトラバースしたいだけです

*[@bob:*] and get the unique set of those.

期待される出力は次のようになります

<doc xmlns:bob="bob.com">
    <element bob:name="fred" bob:occupation="Dr">Stuff</element>
    <element bob:name="Bill" bob:occupation="Dr" bob:birthMonth="Jan"/>
</doc>

1 つの要素は @bob:* 属性を持たないために削除され、もう 1 つの要素は属性のみに基づいて最初の要素の複製であるために削除されました。

キーを使用しようとしましたが、正しく機能していないようです

<xsl:key name="BobAttributes" match="//*" use="./@bob:*" />

また、すべての @bob 属性を連結する関数を作成しようとしましたが、それも期待どおりに機能しないようでした。

<xsl:key name="BobAttributes" match="//*" use="functx:AllBobConcat(.)" />

 <xsl:function name="functx:AllBobConcat" as="xs:string*" 
    xmlns:functx="http://www.functx.com" >
    <xsl:param name="nodes" as="node()*"/> 

    <xsl:for-each select="$nodes/@bob:*">
        <xsl:value-of select="local-name(.)"/>
        <xsl:value-of select="."/>
    </xsl:for-each>
</xsl:function>

どちらの場合も、「単純な」XSL を使用して一意のものを除外していましたが、ここで吹き飛ばしたのでしょうか? 試してデバッグするためにここに追加された変数。

  <xsl:template match="*[@ism:*]" priority="100">
        <xsl:variable name="concat">
            <xsl:value-of select="functx:AllBobConcat(.)"/>
        </xsl:variable>

        <xsl:variable name="myID">
            <xsl:value-of select="generate-id() "/>
        </xsl:variable>

        <xsl:variable name="Keylookup">
            <xsl:value-of select="key('BobAttributes', $concat)"/>
        </xsl:variable>
        <xsl:value-of select="concat($concat, $Keylookup, $myID)"/>
        <xsl:if test="generate-id() = generate-id(key('BobAttributes', $concat)[1])">

            <xsl:apply-templates select="." mode="copy"/>
        </xsl:if>
    </xsl:template>

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

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

私が見落としていた単純なことや、私が取るべきだったまったく異なるクールなアプローチを聞くのを楽しみにしています.

4

2 に答える 2

2

あなたと同じように関数 AllBobConcat を定義し、これをグループ化キーとして使用します。

<xsl:for-each-group select="element" group-by="f:AllBobConcat(.)">
  <xsl:if test="current-grouping-key() != ''">
    <xsl:copy-of select="current-group()[1]"/>
  </xsl:if>
</xsl:for-each-group>

AllBobConcat が属性が正規の順序であることを確認する必要があることを除いて、次のようになります。

<xsl:function name="f:AllBobConcat" as="xs:string">
    <xsl:param name="node" as="element(element)"/> 
    <xsl:value-of>
      <xsl:for-each select="$node/@bob:*">
        <xsl:sort select="local-name()"/>
        <xsl:value-of select="local-name(.)"/>
        <xsl:value-of select="'='"/>
        <xsl:value-of select="."/>
        <xsl:value-of select="' '"/>
      </xsl:for-each>
    </xsl:value-of>
</xsl:function>

また、他の誰かが所有する名前空間に関数を配置するべきではありません。

于 2013-01-27T09:18:09.343 に答える
1

ほぼ間違いなくより良い方法がありますが、FWIW、これは力ずくで、驚くほど手続き的で、恐ろしく非効率的な解決策です。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:bob="bob.com"
    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="this" select="."/>
    <xsl:variable name="match">
      <xsl:for-each select="preceding::element">
        <xsl:variable name="diff">
          <xsl:variable name="that" select="."/>
          <xsl:for-each select="$this/@bob:*">
            <xsl:variable name="att-name" select="name()"/>
            <xsl:variable name="att-val" select="."/>
            <xsl:for-each select="$that/@bob:*[name()=$att-name]">
              <xsl:if test=". != $att-val">
                DIFF
              </xsl:if>
            </xsl:for-each>
          </xsl:for-each>
        </xsl:variable>
        <xsl:if test="$diff = ''">MATCH</xsl:if>
      </xsl:for-each>
    </xsl:variable>

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

</xsl:stylesheet>

要素ごとに、先行するすべての要素をループします。各属性について、値が等しいかどうかを確認し、等しくない場合は DIFF フラグを立てます。DIFF フラグが発生していない先行要素は、MATCH フラグを発生させます。次に、MATCH フラグが立てられなかった場合にのみ要素を通過します。

アセンブリ言語でプログラミングしているように感じます。ここで、Michael がワンライナーの使用deep-equalまたはそのようなものを提供するのを待ちます。

于 2013-01-27T07:25:51.417 に答える