1

SQLServerからデータをXMLとしてクエリすると、重複するXMLノードが生成されることがよくあります。多くの場合、クエリを微調整してこれを排除できますが、常にそうとは限りません。できないときは、次のようなXMLになります。

<Xml>
<House houseId="3" address="123 Main">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
    </Dog>
    <Dog dogId="13" name="Rover">
        <Flea fleaId="23" name="Poindexter" />            
    </Dog>
</House>
<House houseId="3" address="123 Main">
    <Human humanId="9" name="Mr. Johnson">
        <Child childId="11" name="Susie" />
    </Human>
    <Human humanId="9" name="Mr. Johnson">
        <Child childId="31" name="Sandy" />
    </Human>
</House>
<House houseId="5" address="987 Wall">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
    </Dog>
    <Dog dogId="13" name="Rover">
        <Flea fleaId="19" name="Wilhelm" />            
    </Dog>
</House>
</Xml>

属性が同じである2つの<House>ノードが隣り合っていることに注意してください。それらは子ノードのみが異なります。同一の兄弟ノードを取得し、それらをすべての子ノードのスーパーセットを含むものに折りたたむXSLTを作成しようとしています。この例では、<House houseId = "3">には、<Dog>ノードと<Human>ノードの両方が含まれます。このような:

<Xml>
<House houseId="3" address="123 Main">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
        <Flea fleaId="23" name="Poindexter" />            
    </Dog>
    <Human humanId="9" name="Mr. Johnson">
        <Child childId="11" name="Susie" />
        <Child childId="31" name="Sandy" />
    </Human>
</House>
<House houseId="5" address="987 Wall">
    <Dog dogId="13" name="Rover">
        <Flea fleaId="17" name="Chester" />
        <Flea fleaId="19" name="Wilhelm" />            
    </Dog>
</House>
</Xml>

2つの同一のHouseノードが結合されただけでなく、重複したDogノードとHumanノードが結合されました。ただし、2つの異なる<House>ノードの下にリストされている<Dog dogId = '13' name ='Rover'>ノードは、同一ではないため、結合されていないことに注意してください。(彼らの祖先のために。)それが私が目指していることです:一致する兄弟ノードを組み合わせます。

XMLはSQLによって生成されるため、XSLTはさまざまな名前と配置のノードを処理します。したがって、ノード名をハードコーディングすることはできません。ただし、すべてのノードには、数値を含む対応するid属性があります。例:<House houseId = "3">、<Dog dogId = "17">、および<Flea fleaId="13">。
また、ルートノードには属性がないこともわかっているので、ルートの子であるノードの処理を開始できます。

私の戦略は、ノードごとにxsl:keyを作成することです。ここで、ノードのkey-valueは、その祖先ノードとid値の連結です。キー値の例は以下のコメントにあります

<Xml>
<House houseId="3" address="123 Main"><!--"houseId=3"-->
    <Dog dogId="13" name="Rover" ><!--"houseId=3;dogId=13"-->
        <Flea fleaId="17" name="Chester" /><!--"houseId=3;dogId=13;fleaId=17"-->
    </Dog>
    <Dog dogId="13" name="Rover" ><!--"houseId=3;dogId=13"-->
        <Flea fleaId="23" name="Poindexter" /><!--"houseId=3;dogId=13;fleaId=23"-->         
    </Dog>
</House>
<House houseId="3" address="123 Main" ><!--"houseId=3"-->
    <Human humanId="9" name="Mr. Johnson" ><!--"houseId=3;humanId=9"-->
        <Child childId="11" name="Susie" /><!--"houseId=3;humanId=9;childId=11"-->
    </Human>
    <Human humanId="9" name="Mr. Johnson"><!--"houseId=3;humanId=9"-->
        <Child childId="31" name="Sandy" /><!--"houseId=3;humanId=9;childId=31"-->
    </Human>
</House>
<House houseId="5" address="987 Wall" ><!--"houseId=5"-->
    <Dog dogId="13" name="Rover"><!--"houseId=5;dogId=13"-->
        <Flea fleaId="17" name="Chester" /><!--"houseId=5;dogId=13;fleaId=17"-->
    </Dog>
    <Dog dogId="13" name="Rover"><!--"houseId=5;dogId=13"-->
        <Flea fleaId="19" name="Wilhelm" /><!--"houseId=5;dogId=13;fleaId=19"-->           
    </Dog>
</House>
</Xml>

したがって、<Dog dogId = '13' name ='Rover'>の2つの一見一致するオカレンスは、それらの祖先によって区別されます。

<Xml> <House houseId = "3"> <Dog dogId = '13' name ='Rover'>

houseId = 3; dogId = 13

対。

<Xml> <House houseId = "5"> <Dog dogId = '13' name ='Rover'>

houseId = 5; dogId = 13

これにより、重複(兄弟)ノードを組み合わせることができます。残念ながら、XSLとxslt:keyを使用してこれを実装する方法を理解するのに苦労しています。どんな助けでも大歓迎です。

4

1 に答える 1

1

この変換

<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="/*" priority="3">
  <xsl:sequence select="my:grouping(., *)"/>
 </xsl:template>

 <xsl:function name="my:grouping" as="element()*">
  <xsl:param name="pElem" as="element()"/>
  <xsl:param name="pChildren" as="element()*"/>

  <xsl:element name="{name($pElem)}" namespace="{namespace-uri($pElem)}">
   <xsl:apply-templates select="$pElem/@*"/>
   <xsl:for-each-group select="$pChildren" group-by="my:signature(.)">
     <xsl:copy>
       <xsl:apply-templates select="@*|node()[not(self::*)]"/>
       <xsl:apply-templates select=
           "my:grouping(., current-group()/*)/*"/>
     </xsl:copy>
   </xsl:for-each-group>
  </xsl:element>
 </xsl:function>

 <xsl:function name="my:signature" as="xs:string">
  <xsl:param name="pElem" as="element()"/>

  <xsl:variable name="vAttibs" as="xs:string*">
   <xsl:perform-sort select="$pElem/@*">
     <xsl:sort select="name()"/>
   </xsl:perform-sort>
  </xsl:variable>
  <xsl:sequence select=
   "string-join((name($pElem)
                 ,for $at in $vAttibs
                   return concat($at, '+', $pElem/@*[name()=$at])
                 )
                  ,'|')"/>
 </xsl:function>
</xsl:stylesheet>

提供されたXMLドキュメントに適用した場合:

<Xml>
    <House houseId="3" address="123 Main">
        <Dog dogId="13" name="Rover">
            <Flea fleaId="17" name="Chester" />
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="23" name="Poindexter" />
        </Dog>
    </House>
    <House houseId="3" address="123 Main">
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="11" name="Susie" />
        </Human>
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="31" name="Sandy" />
        </Human>
    </House>
    <House houseId="5" address="987 Wall">
        <Dog dogId="13" name="Rover">
            <Flea fleaId="17" name="Chester" />
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="19" name="Wilhelm" />
        </Dog>
    </House>
</Xml>

必要な正しい結果を生成します。

<Xml>
   <House houseId="3" address="123 Main">
      <Dog dogId="13" name="Rover">
         <Flea fleaId="17" name="Chester"/>
         <Flea fleaId="23" name="Poindexter"/>
      </Dog>
      <Human humanId="9" name="Mr. Johnson">
         <Child childId="11" name="Susie"/>
         <Child childId="31" name="Sandy"/>
      </Human>
   </House>
   <House houseId="5" address="987 Wall">
      <Dog dogId="13" name="Rover">
         <Flea fleaId="17" name="Chester"/>
         <Flea fleaId="19" name="Wilhelm"/>
      </Dog>
   </House>
</Xml>

この拡張XMLドキュメント(テキストノードが追加された)を使用すると、次のようになります。

<Xml>
    <House houseId="3" address="123 Main">
        <Dog dogId="13" name="Rover">
          Dog named Rover
            <Flea fleaId="17" name="Chester">Regular dog flee</Flea>
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="23" name="Poindexter">Flea named Poindexter</Flea>
        </Dog>
    </House>
    <House houseId="3" address="123 Main">
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="11" name="Susie">Susan Johnson</Child>
        </Human>
        <Human humanId="9" name="Mr. Johnson">
            <Child childId="31" name="Sandy">Sandy Johnson</Child>
        </Human>
    </House>
    <House houseId="5" address="987 Wall">
        <Dog dogId="13" name="Rover">
            <Flea fleaId="17" name="Chester" />
        </Dog>
        <Dog dogId="13" name="Rover">
            <Flea fleaId="19" name="Wilhelm" />
        </Dog>
    </House>
</Xml>

再び正しい結果が生成されます:

<Xml>
   <House houseId="3" address="123 Main">
      <Dog dogId="13" name="Rover">
          Dog named Rover
            <Flea fleaId="17" name="Chester">Regular dog flee</Flea>
         <Flea fleaId="23" name="Poindexter">Flea named Poindexter</Flea>
      </Dog>
      <Human humanId="9" name="Mr. Johnson">
         <Child childId="11" name="Susie">Susan Johnson</Child>
         <Child childId="31" name="Sandy">Sandy Johnson</Child>
      </Human>
   </House>
   <House houseId="5" address="987 Wall">
      <Dog dogId="13" name="Rover">
         <Flea fleaId="17" name="Chester"/>
         <Flea fleaId="19" name="Wilhelm"/>
      </Dog>
   </House>
</Xml>

説明

2つの関数を使用します:my:signature()my:grouping()

  1. my:signature()各要素の署名を作成します。これは、要素名とすべてのattrName + valueのペアのパイプで区切られた文字列であり、attrNameでソートされます。

  2. my:grouping()my:signature()正しいグループ化を行うために使用します。グループ化する要素を含む2番目の引数があります。

于 2013-01-02T03:41:01.307 に答える