0

ここで明らかな何かが欠けていると思いますが、ここに行きます。以下の xml があり、一致したインスタンスの KEY ノードをグループ化する必要があります。これは match 属性によって指定され、複数の項目番号を含めることができます。ITEM ノードと KEY ノードの数に制限はありません。また、ITEM ノードの深さに制限はありません。また、一致するインスタンスは同じ親の下にある必要はありません。また、XSLT 1.0 と Microsoft パーサーに制限されています。

<?xml version="1.0" encoding="utf-8" ?>
<ITEM number='1'>
  <ITEM number='2'>
    <ITEM number='3' match='5,11'>
      <KEY name='key1' value='x' />
      <KEY name='key2' value='y' />
      <KEY name='key3' value='z' />
      <ITEM number ='4' />
    </ITEM>
    <ITEM number='5' match='3,11'>
      <KEY name='key1' value='x' />
      <KEY name='key2' value='y' />
      <KEY name='key3' value='z' />
    </ITEM>
    <ITEM number='6' match='10'>
      <KEY name='key1' value='x' />
      <KEY name='key2' value='y' />
      <KEY name='key4' value='a' />
    </ITEM>
    <ITEM number='7' />
    <ITEM number='8'>
      <KEY name='key1' value='x' />
    </ITEM>
  </ITEM>
  <ITEM number='9'>
    <ITEM number='10' match='6'>
      <KEY name='key1' value='x' />
      <KEY name='key3' value='z' />
      <KEY name='key5' value='b' />
    </ITEM>
  </ITEM>
    <ITEM number='11' match='3,5'>
      <KEY name='key2' value='y' />
      <KEY name='key3' value='z' />
    </ITEM>
</ITEM>

私の期待される結果は次のようになります...

<?xml version="1.0" encoding="utf-8" ?>
<Result>
  <Group number="1" />
  <Group number="2" />
  <Group number="3,5,11">
    <KEY name='key1' value='x' />
    <KEY name='key2' value='y' />
    <KEY name='key3' value='z' />
  </Group>
  <Group number="4" />
  <Group number="6,10">
    <KEY name='key1' value='x' />
    <KEY name='key2' value='y' />
    <KEY name='key3' value='z' />
    <KEY name='key4' value='a' />
    <KEY name='key5' value='b' />
  </Group>
  <Group number="7" />
  <Group number="8">
    <KEY name='key1' value='x' />
  </Group>
  <Group number="9" />
</Result>

私が実際に得るものは...

<?xml version="1.0" encoding="utf-8"?>
<Result>
  <Group number="1" />
  <Group number="2" />
  <Group number="3,5,11">
    <KEY name="key1" value="x" />
    <KEY name="key2" value="y" />
    <KEY name="key3" value="z" />
  </Group>
  <Group number="4" />
  <Group number="6,10">
    <KEY name="key4" value="a" />
    <KEY name="key5" value="b" />
  </Group>
  <Group number="7" />
  <Group number="8" />
  <Group number="9" />
</Result>

キーを使用していますが、キー関数からその特定の値にアクセスすると、再度アクセスできないようです。グループ番号 6,10 には 5 つのキーがすべて含まれているはずですが、グループ番号 3,5 に既に存在する最初の 3 つがありません。グループ番号 8 についても同様に、1 つのキーが含まれている必要があります。一致したインスタンスをスキップするために再帰を使用しましたが、そこに問題はないと思います。主要な機能に関連しているようです。以下に xslt を添付しました。よく見て、何が間違っているのか教えてください。パフォーマンスを向上させるためのヒントも大歓迎です:)

<?xml version="1.0" encoding="utf-8"?>
<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:output method="xml" indent="yes"/>

  <xsl:key name="kKeyByName" match="KEY" use="@name" />

  <xsl:template name="ProcessItem">
    <!--pItemsList - node set containing items that need to be processed-->
    <xsl:param name="pItemsList" />
    <!--pProcessedList - string containing processed item numbers in the format |1|2|3|-->
    <xsl:param name="pProcessedList" />

    <xsl:variable name="vCurrItem" select="$pItemsList[1]" />
    <!--Recursion exit condition - check if we have a valid Item-->
    <xsl:if test="$vCurrItem">
      <xsl:variable name="vNum" select="$vCurrItem/@number" />
      <!--Skip processed instances-->
      <xsl:if test="not(contains($pProcessedList, concat('|', $vNum, '|')))">
        <xsl:element name="Group">
          <!--If the item is matched with another item, only the distinct keys of the 2 should be displayed-->
          <xsl:choose>
            <xsl:when test="$vCurrItem/@match">
              <xsl:attribute name="number">
                <xsl:value-of select="concat($vNum, ',', $vCurrItem/@match)" />
              </xsl:attribute>
              <xsl:for-each select="(//ITEM[@number=$vNum or @match=$vNum]/KEY)[generate-id(.)=generate-id(key('kKeyByName', @name)[1])]">
                <xsl:apply-templates select="." />
              </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
              <xsl:attribute name="number">
                <xsl:value-of select="$vNum" />
              </xsl:attribute>
              <xsl:apply-templates select="KEY" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:element>
      </xsl:if>

      <!--Append processed instances to list to pass on in recursive function-->
      <xsl:variable name="vNewList">
        <xsl:value-of select="$pProcessedList" />
        <xsl:value-of select="concat($vNum, '|')" />
        <xsl:if test="$vCurrItem/@match">
          <xsl:value-of select="concat($vCurrItem/@match, '|')" />
        </xsl:if>
      </xsl:variable>

      <!--Call template recursively to process the rest of the instances-->
      <xsl:call-template name="ProcessItem">
        <xsl:with-param name="pItemsList" select="$pItemsList[position() > 1]" />
        <xsl:with-param name="pProcessedList" select="$vNewList" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

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

  <xsl:template match="/">
    <xsl:element name="Result">
      <xsl:call-template name="ProcessItem">
        <xsl:with-param name="pItemsList" select="//ITEM" />
        <xsl:with-param name="pProcessedList" select="'|'" />
      </xsl:call-template>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
4

1 に答える 1

0

各アイテムに一致するものが 1 つしかない場合、または一致しない場合は、次の xslt を試してください。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:key name="kItemNr" match="ITEM" use="@number" />
    <xsl:key name="kNumberKey" match="KEY" use="concat(../@number, '|', @name )" />

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

        </xsl:template>

    <xsl:template match="ITEM">
        <xsl:if test="not(preceding::ITEM[@number = current()/@match])" >
            <Group>
                <xsl:attribute name="number">
                    <xsl:value-of select="@number"/>
                    <xsl:if test="@match" >
                        <xsl:text>,</xsl:text>
                        <xsl:value-of select="@match"/>
                    </xsl:if>
                </xsl:attribute>
                <xsl:variable name="itemNr" select="@number"/>
                <xsl:apply-templates select="KEY |  key('kItemNr',@match )/KEY[ 
                                     not (key('kNumberKey', concat($itemNr, '|', @name) ) )] ">
                    <xsl:sort select="@name"/>
                </xsl:apply-templates>

            </Group>
        </xsl:if>
    </xsl:template>
    <xsl:template match="/" >
        <Result>
            <xsl:for-each select="//ITEM[count(. |  key('kItemNr',number )  ) = 1 ]" >
                <xsl:apply-templates select="." />
            </xsl:for-each>
        </Result>
    </xsl:template>

</xsl:stylesheet>

次の出力が生成されます。

<?xml version="1.0"?>
<Result>
  <Group number="1"/>
  <Group number="2"/>
  <Group number="3,5">
    <KEY name="key1" value="x"/>
    <KEY name="key2" value="y"/>
    <KEY name="key3" value="z"/>
  </Group>
  <Group number="4"/>
  <Group number="6,10">
    <KEY name="key1" value="x"/>
    <KEY name="key2" value="y"/>
    <KEY name="key3" value="z"/>
    <KEY name="key4" value="a"/>
    <KEY name="key5" value="b"/>
  </Group>
  <Group number="7"/>
  <Group number="8">
    <KEY name="key1" value="x"/>
  </Group>
  <Group number="9"/>
</Result>

変更されたリクエストによる更新:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes"/>

    <xsl:key name="kItemNr" match="ITEM" use="@number" />

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

    <xsl:template match="ITEM">
        <xsl:variable name="matchStr" select=" concat(',', current()/@match, ',')"/>
        <xsl:if test="not(preceding::ITEM[ contains($matchStr, concat(',', @number, ',') )])" >
            <Group>
                <xsl:attribute name="number">
                    <xsl:value-of select="@number"/>
                    <xsl:if test="@match" >
                        <xsl:text>,</xsl:text>
                        <xsl:value-of select="@match"/>
                    </xsl:if>
                </xsl:attribute>

                <xsl:apply-templates select="(KEY | 
                                     //ITEM[ 
                                        contains( $matchStr, concat(',', @number, ',') )
                                    ]/KEY[
                                         not((preceding::ITEM[
                                             contains( $matchStr, concat(',', @number, ',') )
                                            ] | current() )/KEY/@name = @name)
                                     ]) ">
                    <xsl:sort select="@name"/>
                </xsl:apply-templates>

            </Group>

        </xsl:if>
    </xsl:template>
    <xsl:template match="/" >
        <Result>
            <xsl:for-each select="//ITEM[count(. |  key('kItemNr',number )  ) = 1 ]" >
                <xsl:apply-templates select="." />
            </xsl:for-each>
        </Result>

    </xsl:template>

</xsl:stylesheet>

これは、より大きな入力データの場合は非常に遅くなる可能性がありますが、とにかく.

于 2013-05-24T06:52:29.743 に答える