2011-12-04 5 views
1

変数に項目のリストを作成しようとしていますが、その項目がすでにリストに入っているかどうかを確認したいのですが。 項目は、私の質問にとってはあまり重要ではない入力文書によって与えられます。作成中のXSLT読み取り/変更結果ツリー

私は解決しようとしている2つの問題があります。

1:私は現在、

2を生成してい変数からデータを読み込む:ここでは、変数

内のノードにテキストを追加することは、私がこれまで試したものです:

<xsl:variable name="data"> 
    <list> 
     <xsl:call-template name="generate"/> 
    </list> 
</xsl:variable> 


<xsl:template name="generate" match="/"> 
    <xsl:apply-templates select="//thing"/> 
</xsl:template> 


<xsl:template match="//thing"> 
    <xsl:variable name="temp"> 
     <xsl:value-of select="./text()"/> 
    </xsl:variable> 

    <xsl:choose> 
     <!-- test however this thing is already in $data --> 
     <!-- problem #1: here, trying to read anything out of $data doesn't work --> 
     <xsl:when test="contains($data/list/item/text(), $temp/text())"> 
      <xsl:for-each select="$data/list/item"> 
       <xsl:if test="contains(./text(), $temp/text())"> 
        <!-- problem #2: append any string to self::node()/text() --> 
       </xsl:if> 
      </xsl:for-each> 
     </xsl:when> 
     <xsl:otherwise> 
      <item> 
       <xsl:value-of name="$temp/text()"/> 
      </item> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

私は結果ツリーの断片などをたくさん検索しましたが、どうやってそれを行うのか分かりませんでした。

編集: これは、入力コードのようになります。

<data> 
<thing>string1</thing> 
<thing>string2</thing> 
<thing>string3</thing> 
<nested><thing>string1</thing></nested> 
<nested><thing>string1</thing></nested> 
<nested><thing>string2</thing></nested> 
</data> 

出力:

<list> 
<item>string1 string1 string1</item> 
<item>string2 string2</item> 
<item>string3</item> 
</list> 

クリス

+0

作成したいXML入力のサンプルとそれに対応する出力を投稿することを検討してください。これを実現するためのXSLTアプローチを提案できます。私はあなたの現在の問題の記述が手続き的すぎるのではないかと心配しています.XSLTは宣言型言語です。 –

+0

入力ファイルが非常に複雑なので、サンプルの入力を投稿するのは簡単ではないので、そのサンプルコードを小さくしてみました。試してみます... – Chris

+0

どうぞお試しください。または、XSLT(XSLT 1.0:http://www.jenitennison.com/xslt/grouping/muenchian.xml、XSLT 2.0:http://www.w3.org/TR/xslt20/#grouping-examples)のグループ化についてお読みください)、私の現在の推測はあなたが必要とするXSLTのアプローチです。 –

答えて

5

<data> 
<thing>string1</thing> 
<thing>string2</thing> 
<thing>string3</thing> 
<nested><thing>string1</thing></nested> 
<nested><thing>string1</thing></nested> 
<nested><thing>string2</thing></nested> 
</data> 

NPUTこれは、(独立マーティン豊年から)私の答えですが、私はそれはあなたの主な質問に答えていないことを認識- ツリーをトラバースする方法既に蓄積されたデータを処理する場合には、データを処理して累積する。私は、この変換が提供されるXML文書に適用されるとき、これは

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

<xsl:key name="kThingByVal" match="thing" 
    use="."/> 

<xsl:template match="/"> 
    <list> 
     <xsl:apply-templates select= 
     "//thing 
      [generate-id() 
      = 
      generate-id(key('kThingByVal', .)[1]) 
      ] 
     "> 
     </xsl:apply-templates> 
    </list> 
</xsl:template> 

<xsl:template match="thing"> 
    <item> 
    <xsl:apply-templates mode="gen" 
     select="key('kThingByVal', .)"/> 
    </item> 
</xsl:template> 

<xsl:template match="thing" mode="gen"> 
    <xsl:if test="not(position() = 1)"> 
    <xsl:text> </xsl:text> 
    </xsl:if> 
    <xsl:value-of select="."/> 
</xsl:template> 
</xsl:stylesheet> 

...私の答えの第二部で解決策を望ん提供:

<data> 
    <thing>string1</thing> 
    <thing>string2</thing> 
    <thing>string3</thing> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string2</thing> 
    </nested> 
</data> 

指名手配、正しい結果が生産されます:

<list> 
    <item>string1 string1 string1</item> 
    <item>string2 string2</item> 
    <item>string3</item> 
</list> 

II。この問題の一般的な解決方法は、にあります。

FXSLのf:foldl()などの関数を使ってリストを処理するのと同じ方法でツリーを処理したいと考えています。

ここに古典的なアプリケーションの使い方を示すf:foldl()(XSLT 1の場合。

testFoldl.xsl

<xsl:stylesheet version="1.0" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:foldr-func="foldr-func" 
exclude-result-prefixes="xsl f foldr-func" 
> 

    <xsl:import href="foldl.xsl"/> 

    <!-- This transformation must be applied to: 
     numList.xml 
    --> 
    <foldr-func:foldr-func/> 
    <xsl:variable name="vFoldrFun" select="document('')/*/foldr-func:*[1]"/> 
    <xsl:output encoding="UTF-8" omit-xml-declaration="yes"/> 

    <xsl:template match="/"> 

     <xsl:call-template name="foldl"> 
     <xsl:with-param name="pFunc" select="$vFoldrFun"/> 
     <xsl:with-param name="pList" select="/*/*"/> 
     <xsl:with-param name="pA0" select="0"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template mode="f:FXSL" 
     match="foldr-func:*"> 
     <xsl:param name="arg1" select="0"/> 
     <xsl:param name="arg2" select="0"/> 

     <xsl:value-of select="$arg1 + $arg2"/> 
    </xsl:template> 

</xsl:stylesheet> 
0これは、電流積算結果と海流リスト項目を取り、新たな結果を生成する任意の機能を任意のリストを処理することができる)テンプレート、ないxsl:functionあります

この変換は(番号のリストを表す)このXML文書に適用される:

<nums> 
    <num>01</num> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <num>05</num> 
    <num>06</num> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 

指名手配結果(すべてのリスト項目の合計)が生成されます

55 

すると、我々がパラメータとしてではないadd()機能が、mult()関数を渡す(および場合は、リストから0を削除することを、メモしています新しい "ゼロ"パラメータ - 1 - 乗算のニュートラル数を指定すると、すべてのリスト項目の積 - 10!(10階乗)が得られます。

したがって、f:foldl()は、累積結果と現在のリスト項目に基づいて新しい結果が生成されるすべてのリストを処理するために使用できる非常に強力な関数です。

このトピックが興味深いと思われる場合は、もっと面白いものがありますhere

倍-tree2.xsl

は興味深いことに、ツリーを処理し、同様の機能が存在する

ここ
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:ext="http://exslt.org/common" 
exclude-result-prefixes="f ext msxsl xsl" 
> 
<xsl:template name="foldl-tree2"> 
    <xsl:param name="pFuncNode" select="/.."/> 
    <xsl:param name="pFuncSubtrees" select="/.."/> 
    <xsl:param name="pA0"/> 
    <xsl:param name="pNode" select="/.."/> 

    <xsl:choose> 
    <xsl:when test="not($pNode)"> 
      <xsl:copy-of select="$pA0"/> 
    </xsl:when> 

    <xsl:otherwise> 
    <xsl:variable name="vSubtrees" select="$pNode/*"/> 

    <xsl:variable name="vSubTreeResult"> 
     <xsl:call-template name="foldl-tree_"> 
     <xsl:with-param name="pFuncNode" select="$pFuncNode"/> 
     <xsl:with-param name="pFuncSubtrees" select="$pFuncSubtrees"/> 
     <xsl:with-param name="pA0" select="$pA0"/> 
     <xsl:with-param name="pSubTrees" select="$vSubtrees"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:apply-templates select="$pFuncNode[1]" mode="f:FXSL"> 
    <xsl:with-param name="arg0" select="$pFuncNode[position() > 1]"/> 
    <xsl:with-param name="arg1" select="$pNode"/> 
    <xsl:with-param name="arg2" select="ext:node-set($vSubTreeResult)"/> 
    </xsl:apply-templates> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="foldl-tree_"> 
    <xsl:param name="pFuncNode" select="/.."/> 
    <xsl:param name="pFuncSubtrees" select="/.."/> 
    <xsl:param name="pA0"/> 
    <xsl:param name="pSubTrees" select="/.."/> 

    <xsl:choose> 
    <xsl:when test="not($pSubTrees)"> 
      <xsl:copy-of select="$pA0"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:variable name="vSubTree1Result"> 
     <xsl:call-template name="foldl-tree2"> 
      <xsl:with-param name="pFuncNode" select="$pFuncNode"/> 
      <xsl:with-param name="pFuncSubtrees" select="$pFuncSubtrees"/> 
      <xsl:with-param name="pA0" select="$pA0"/> 
      <xsl:with-param name="pNode" select="$pSubTrees[1]"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:variable name="vRestSubtreesResult"> 
     <xsl:call-template name="foldl-tree_"> 
      <xsl:with-param name="pFuncNode" select="$pFuncNode"/> 
      <xsl:with-param name="pFuncSubtrees" select="$pFuncSubtrees"/> 
      <xsl:with-param name="pA0" select="$pA0"/> 
      <xsl:with-param name="pSubTrees" select="$pSubTrees[position() > 1]"/> 
     </xsl:call-template> 
     </xsl:variable> 

    <xsl:apply-templates select="$pFuncSubtrees" mode="f:FXSL"> 
     <xsl:with-param name="arg0" select="$pFuncSubtrees[position() > 1]"/> 
     <xsl:with-param name="arg1" select="ext:node-set($vSubTree1Result)"/> 
     <xsl:with-param name="arg2" select="ext:node-set($vRestSubtreesResult)"/> 
    </xsl:apply-templates> 
    </xsl:otherwise> 
    </xsl:choose>  
</xsl:template> 
</xsl:stylesheet> 

、ツリーの他に、ゼロ(初期結果)と各木ノード(累積結果とともに)を処理する関数として、ツリーノードのすべての部分木とそれまでの累積結果の集合をとる関数をパラメータとして渡し、新しい結果を生成します。また、ツリーの最上位ノードにパラメータとして渡す必要があります。

試験foldlTree2:ここ

foldl-tree2()を使用して簡単な図です。XSL

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:add-tree="add-tree" 
xmlns:f="http://fxsl.sf.net/" 
exclude-result-prefixes="xsl f add-tree" 
> 
    <xsl:import href="foldl-tree2.xsl"/> 

    <xsl:strip-space elements="*"/> 
    <add-tree:add-tree/> 

    <xsl:output method="text"/> 

    <xsl:template match="/"> 
     <xsl:variable name="vAdd" select="document('')/*/add-tree:*[1]"/> 

     <xsl:call-template name="foldl-tree2"> 
     <xsl:with-param name="pFuncNode" select="$vAdd"/> 
     <xsl:with-param name="pFuncSubtrees" select="$vAdd"/> 
     <xsl:with-param name="pA0" select="0"/> 
     <xsl:with-param name="pNode" select="/*"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template match="add-tree:*" mode="f:FXSL"> 
     <xsl:param name="arg1"/> 
     <xsl:param name="arg2"/> 

     <xsl:variable name="varg1"> 
     <xsl:call-template name="nodeValue"> 
     <xsl:with-param name="pNode" select="$arg1"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:variable name="varg2"> 
     <xsl:call-template name="accumValue"> 
     <xsl:with-param name="pAccum" select="$arg2"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:value-of select="$varg1 + $varg2"/> 
    </xsl:template> 

    <xsl:template name="nodeValue"> 
    <xsl:param name="pNode"/> 
    <xsl:call-template name="toNumber"> 
     <xsl:with-param name="pX" select="$pNode/text()[1]"/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="accumValue"> 
    <xsl:param name="pAccum"/> 
    <xsl:call-template name="toNumber"> 
     <xsl:with-param name="pX" select="$pAccum"/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="toNumber"> 
    <xsl:param name="pX"/> 

    <xsl:choose> 
     <xsl:when test="not(number($pX) = number($pX))">0</xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="number($pX)"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

この変換は任意の木に適用されると、そのテキストノード番号が含まれているいくつかの:

<nums> 
    <a> 
    <b> 
    <num>01</num> 
    </b> 
    </a> 
    <c> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <d> 
    <num>05</num> 
    <num>06</num> 
    </d> 
    </c> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 

それはすべて、このような数字の合計を生成します。

55 

ここでは、異なるパラメータをに渡すだけです元の問題によって要求されるそれは、別個item下で全て同じ値と、全てthing要素値の発生回数のリストを抽出します。この変換は、元々設けXMLに適用さ

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:ext="http://exslt.org/common" 
xmlns:merge-list="merge-list" 
xmlns:f="http://fxsl.sf.net/" 
exclude-result-prefixes="xsl f ext msxsl merge-list" 
> 
    <xsl:import href="foldl-tree2.xsl"/> 

    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <merge-list:merge-list/> 

    <xsl:variable name="vrtfZero"> 
    <list/> 
    </xsl:variable> 

    <xsl:variable name="vZero" select= 
    "document('')/*/xsl:variable[@name='vrtfZero']/* 
    "/> 

    <xsl:template match="/"> 
     <xsl:variable name="vFunMerge" select="document('')/*/merge-list:*[1]"/> 

     <list> 
     <xsl:call-template name="foldl-tree2"> 
     <xsl:with-param name="pFuncNode" select="$vFunMerge"/> 
     <xsl:with-param name="pFuncSubtrees" select="$vFunMerge"/> 
     <xsl:with-param name="pA0" select="$vZero"/> 
     <xsl:with-param name="pNode" select="/*"/> 
     </xsl:call-template> 
     </list> 
    </xsl:template> 

    <xsl:template match="merge-list:*" mode="f:FXSL"> 
     <xsl:param name="arg1"/> 
     <xsl:param name="arg2"/> 

     <xsl:variable name="vrtfArg1"> 
     <xsl:apply-templates mode="gen" select="$arg1"/> 
     </xsl:variable> 

     <xsl:variable name="vrtfArg2"> 
     <xsl:apply-templates mode="gen" select="$arg2"/> 
     </xsl:variable> 

     <xsl:variable name="vArg1" select="ext:node-set($vrtfArg1)/*"/> 
     <xsl:variable name="vArg2" select="ext:node-set($vrtfArg2)/*"/> 

     <xsl:for-each select="$vArg1[self::thing or self::item]"> 
     <xsl:variable name="vMatch" select= 
     "$vArg2[self::thing or self::item 
       and 
       substring-before(concat(., ' '), ' ') 
       = 
       substring-before(concat(current(), ' '), ' ') 
       ]"/> 
     <xsl:choose> 
      <xsl:when test="$vMatch"> 
      <item> 
      <xsl:value-of select="$vMatch/text()"/> 
      <xsl:text> </xsl:text> 
      <xsl:value-of select="."/> 
      </item> 
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:copy-of select="."/> 
      </xsl:otherwise> 
     </xsl:choose> 
     </xsl:for-each> 

     <xsl:for-each select="$vArg2[self::thing or self::item]"> 
     <xsl:variable name="vMatch" select= 
     "$vArg1[self::thing or self::item 
       and 
       substring-before(concat(., ' '), ' ') 
       = 
       substring-before(concat(current(), ' '), ' ') 
       ]"/> 
      <xsl:if test="not($vMatch)"> 
      <xsl:copy-of select="."/> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="thing" mode="gen"> 
    <item><xsl:value-of select="."/></item> 
    </xsl:template> 

    <xsl:template match="item" mode="gen"> 
    <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="*" mode="gen"/> 

    <xsl:template mode="gen" match="/"> 
    <xsl:apply-templates select="*" mode="gen"/> 
    </xsl:template> 
</xsl:stylesheet> 

文書:指名手配、正しい結果がを生産している

<data> 
    <thing>string1</thing> 
    <thing>string2</thing> 
    <thing>string3</thing> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string1</thing> 
    </nested> 
    <nested> 
     <thing>string2</thing> 
    </nested> 
</data> 

<list> 
    <item>string1 string1 string1</item> 
    <item>string2 string2</item> 
    <item>string3</item> 
</list> 
+0

「ツリーをトラバースして処理し、データが蓄積されたデータを処理する方法」これはまさに私が試しているものです:)返信を待っています – Chris

+0

@Chris:今朝早くご使用でした。これで今作業する。 :) –

+0

@Chris:完了。 :) –

2

スタイルシート

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

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

    <xsl:key name="k1" match="thing" use="."/> 

    <xsl:template match="data"> 
    <list> 
     <xsl:apply-templates select="descendant::thing[generate-id() = generate-id(key('k1', .)[1])]" mode="group"/> 
    </list> 
    </xsl:template> 

    <xsl:template match="thing" mode="group"> 
    <item> 
     <xsl:apply-templates select="key('k1', .)"/> 
    </item> 
    </xsl:template> 

    <xsl:template match="thing"> 
    <xsl:if test="position() &gt; 1"> 
     <xsl:text> </xsl:text> 
    </xsl:if> 
    <xsl:value-of select="."/> 
    </xsl:template> 

</xsl:stylesheet> 

は私を変換します出力

<list> 
    <item>string1 string1 string1</item> 
    <item>string2 string2</item> 
    <item>string3</item> 
</list> 
+0

ありがとうございました!自分のアプリケーションでこのようなグループ化機能を使用できるかどうかがわかります。 – Chris

関連する問題