複数の属性の値の重複したノードベースを排除する方法は?

StackOverflow https://stackoverflow.com/questions/4613267

  •  26-09-2019
  •  | 
  •  

質問

複数の(1を超える)属性の値に基づいて重複したノードを排除するにはどうすればよいですか?また、属性名はスタイルシートのパラメーターとして渡されます。今、私は、 <xsl:key> エレメント。しかし、私はXSLT 1.0がパラメーター/変数を許可していないことを知るようになりました <xsl:key>.

重複したノードの削除を実現する別の方法はありますか?ミュンケアの方法ほど効率的でない場合は問題ありません。

Previusからの更新 質問:

XML:

<data id = "root">
  <record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/>
  <record id="2" operator1='abc' operator2='yyy' operator3='zzz'/>
  <record id="3" operator1='abc' operator2='yyy' operator3='zzz'/>
  <record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/>
  <record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/>
  <record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/>
  <record id="7" operator1='abc' operator2='yyy' operator3='zzz'/>
  <record id="8" operator1='abc' operator2='yyy' operator3='zzz'/>
  <record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/>
  <record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/>
</data>
役に立ちましたか?

解決

この変換を使用します (シンプルで、新しいStyleSheetを生成する必要はありません):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pAttribs">
 <name>operator1</name>
 <name>operator2</name>
 <name>operator3</name>
 </xsl:param>

 <xsl:variable name="vAttribs" select=
    "document('')/*/xsl:param[@name='pAttribs']"/>

 <xsl:key name="kRecByAtts" match="record"
   use="@___g_key"/>

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

 <xsl:template match="/">
 <xsl:variable name="vrtdPass1">
   <xsl:apply-templates/>
 </xsl:variable>

 <xsl:variable name="vPass1" select=
  "ext:node-set($vrtdPass1)/*"/>

 <xsl:apply-templates select="$vPass1"/>
 </xsl:template>

 <xsl:template match="record[not(@___g_key)]">
 <xsl:copy>
   <xsl:copy-of select="@*"/>

   <xsl:attribute name="___g_key">
    <xsl:for-each select="@*[name()=$vAttribs/name]">
      <xsl:sort select="name()"/>

       <xsl:value-of select=
          "concat('___Attrib___',name(),'___Value___',.,'+++')"/>
    </xsl:for-each>
   </xsl:attribute>
 </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "record[@___g_key]
         [not(generate-id()
             =
               generate-id(key('kRecByAtts', @___g_key)[1])
              )
          ]
   "/>

  <xsl:template match="@___g_key"/>
</xsl:stylesheet>

以前の質問のXMLドキュメントに適用された場合:

<data id = "root">
    <record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/>
    <record id="2" operator1='abc' operator2='yyy' operator3='zzz'/>
    <record id="3" operator1='abc' operator2='yyy' operator3='zzz'/>
    <record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/>
    <record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/>
    <record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/>
    <record id="7" operator1='abc' operator2='yyy' operator3='zzz'/>
    <record id="8" operator1='abc' operator2='yyy' operator3='zzz'/>
    <record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/>
    <record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/>
</data>

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

<data id="root">
   <record id="1" operator1="xxx" operator2="yyy" operator3="zzz"/>
   <record id="2" operator1="abc" operator2="yyy" operator3="zzz"/>
   <record id="5" operator1="xxx" operator2="lkj" operator3="tyu"/>
   <record id="10" operator1="rrr" operator2="yyy" operator3="zzz"/>
</data>

他のヒント

2つのステップでの単一の変換のためのその他のアプローチ:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="msxsl">
    <xsl:key name="kItemByLocal" match="record[@local-key]" use="@local-key"/>
    <xsl:param name="pAttNames" select="'operator1 operator2 operator3'"/>
    <xsl:template match="/">
        <xsl:variable name="vFirstRTF">
            <xsl:apply-templates/>
        </xsl:variable>
        <xsl:apply-templates select="msxsl:node-set($vFirstRTF)/node()"/>
    </xsl:template>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="record[not(@local-key)]">
        <xsl:copy>
            <xsl:attribute name="local-key">
                <xsl:call-template name="local-key"/>
            </xsl:attribute>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="record[@local-key]
                               [count(.|key('kItemByLocal',@local-key)[1])
                                 != 1]|@local-key"/>
    <xsl:template name="local-key">
        <xsl:param name="pAttributes" select="concat($pAttNames,' ')"/>
        <xsl:if test="normalize-space($pAttributes)">
            <xsl:variable name="vName"
                          select="substring-before($pAttributes,' ')"/>
            <xsl:variable name="vAttribute" select="@*[name()=$vName]"/>
            <xsl:value-of select="concat($vName,'+',$vAttribute,'+')"/>
            <xsl:call-template name="local-key">
                <xsl:with-param name="pAttributes"
                                select="substring-after($pAttributes,' ')"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

出力:

<data id="root">
    <record id="1" operator1="xxx" operator2="yyy" operator3="zzz"></record>
    <record id="2" operator1="abc" operator2="yyy" operator3="zzz"></record>
    <record id="5" operator1="xxx" operator2="lkj" operator3="tyu"></record>
    <record id="10" operator1="rrr" operator2="yyy" operator3="zzz"></record>
</data>

編集: :また、名前付きテンプレートなし @local-key 世代

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="msxsl">
    <xsl:key name="kItemByLocal" match="record[@local-key]" use="@local-key"/>
    <xsl:param name="pAttNames" select="'operator1 operator2 operator3'"/>
    <xsl:template match="/">
        <xsl:variable name="vFirstRTF">
            <xsl:apply-templates/>
        </xsl:variable>
        <xsl:apply-templates select="msxsl:node-set($vFirstRTF)/node()"/>
    </xsl:template>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="record[not(@local-key)]">
        <xsl:variable name="vAttNames"
                      select="concat(' ',$pAttNames,' ')"/>
        <xsl:copy>
            <xsl:attribute name="local-key">
                <xsl:for-each select="@*[contains(
                                             $vAttNames,
                                             concat(' ',name(),' ')
                                                 )]">
                    <xsl:sort select="substring-before(
                                             $vAttNames,
                                             concat(' ',name(),' ')
                                                      )"/>
                    <xsl:value-of select="concat(name(),'++',.,'++')"/>
                </xsl:for-each>
            </xsl:attribute>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="record[@local-key]
                               [count(.|key('kItemByLocal',@local-key)[1])
                                 != 1]|@local-key"/>
</xsl:stylesheet>

ノート: :属性がすべての要素で同じであることを確信している場合は、並べ替えを削除できます。

属性名をパラメーターとして渡す場合、1つのアプローチは、最初のステップがXML入力を取得し、単に属性名と要素名をパラメーターとして使用して2番目のスタイルシートを生成する2段階の変換である可能性があります。 。これが最初のスタイルシートの例です。

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
  exclude-result-prefixes="axsl exsl"  
  version="1.0">

  <xsl:param name="parent-name" select="'items'"/>
  <xsl:param name="element-name" select="'item'"/>
  <xsl:param name="att-names" select="'att1,att2'"/>
  <xsl:param name="sep" select="'|'"/>

  <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:variable name="key-value">
    <xsl:text>concat(</xsl:text>
    <xsl:call-template name="define-values">
      <xsl:with-param name="att-names" select="$att-names"/>
    </xsl:call-template>
    <xsl:text>)</xsl:text>
  </xsl:variable>

  <xsl:template name="define-values">
    <xsl:param name="att-names"/>
    <xsl:choose>
      <xsl:when test="contains($att-names, ',')">
        <xsl:value-of select="concat('@', substring-before($att-names, ','), ',&quot;', $sep, '&quot;,')"/>
        <xsl:call-template name="define-values">
          <xsl:with-param name="att-names" select="substring-after($att-names, ',')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat('@', $att-names)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="/">
    <axsl:stylesheet version="1.0">
      <axsl:output indent="yes"/>
      <axsl:key name="k1" match="{$parent-name}/{$element-name}" use="{$key-value}"/>
      <axsl:template match="@* | node()">
        <axsl:copy>
          <axsl:apply-templates select="@* | node()"/>
        </axsl:copy>
      </axsl:template>
      <axsl:template match="{$parent-name}">
        <axsl:copy>
          <axsl:apply-templates select="@*"/>
          <axsl:apply-templates select="{$element-name}[generate-id() = generate-id(key('k1', {$key-value})[1])]"/>
        </axsl:copy>
      </axsl:template>
    </axsl:stylesheet>
  </xsl:template>

</xsl:stylesheet>

4つのパラメーターが必要です。

  1. parent-name: :重複を排除したい要素を含む要素の名前
  2. element-name: :重複を排除したい要素の名前
  3. att-names: :属性名のコンマ分離リスト
  4. sep: :入力XMLの属性値で発生しないセパレータ文字

次に、StyleSheetは、重複を排除するためにMuenchianグループ化を適用する2番目のスタイルシートを生成します。たとえば、StyleSheet Saxon 6.5.5に記載されているデフォルトのパラメーターを使用すると、次のスタイルシートが生成されます。

<axsl:stylesheet xmlns:axsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <axsl:output indent="yes"/>
   <axsl:key name="k1" match="items/item" use="concat(@att1,&#34;|&#34;,@att2)"/>
   <axsl:template match="@* | node()">
      <axsl:copy>
         <axsl:apply-templates select="@* | node()"/>
      </axsl:copy>
   </axsl:template>
   <axsl:template match="items">
      <axsl:copy>
         <axsl:apply-templates select="@*"/>
         <axsl:apply-templates select="item[generate-id() = generate-id(key('k1', concat(@att1,&#34;|&#34;,@att2))[1])]"/>
      </axsl:copy>
   </axsl:template>
</axsl:stylesheet>

これは、次のようなXMLドキュメントに適用できます

<items>
  <item att1="a" att2="1" att3="A"/>
  <item att1="b" att2="1" att3="A"/>
  <item att1="a" att2="1" att3="B"/>
  <item att1="c" att2="2" att3="A"/>
  <item att1="d" att2="3" att3="C"/>
</items>

そして、出力はです

<items>
   <item att1="a" att2="1" att3="A"/>
   <item att1="b" att2="1" att3="A"/>
   <item att1="c" att2="2" att3="A"/>
   <item att1="d" att2="3" att3="C"/>
</items>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top