2011-06-24 16 views
2

「for-each-group」の作業に苦労しています。私は最近xslt 2に切り替えましたが、それをすべて理解するためにはまだいくつかの仕事があります。私はFramemaker MIF(フラットXML)から受け取ったいくつかのファイルを整理しようとしていますが、ほとんどの場合、データはかなりきれいですが、それはナットを駆動する例外です。私はいくつかの典型的な例を以下のXMLに組み合わせました。使用例はアンダーラインタグに関連していますが、原則としてファイルは次のようにビルドされています:[アンダーライン/]タグが表示されている場合、[EndUnderline /]タグに達するまで兄弟に下線を付ける必要がありますこれら両方のタグを取り除き、すべての兄弟を1つの[u]タグにカプセル化します。しかし、実際の[EndUnderline /]タグに達するまで、無視する必要のある[アンダーライン/]タグが続くことがあります。XSLT:複雑なグループ化の問題

これは単純化されたXMLファイルである、のは、上記より見やすくしてみましょう:

<TestFile> 
<!-- Para tag containing no underline tags --> 
<Para> 
    <Content>[text_not_underlined]</Content> 
</Para> 

<!-- correct encapsulation from source --> 
<Para> 
<Content> 
    <Underline/>[text_to_be_underlined]<EndUnderline/> 
    <p>Some test data</p> 
</Content> 
</Para> 

<!-- extra underline tag that should be ignored --> 
<Para> 
<Content> 
    <Underline/>[text_to_be_underlined] 
    <Underline/> 
    <EndUnderline/> 
    <p>Some other test data</p> 
</Content> 
</Para> 

<!-- some extra end underline tags that should be ignored --> 
<Para> 
<Content> 
    <EndUnderline/>[no_longer_underline]<EndUnderline/> 
    <p>: More data</p> 
</Content> 
</Para> 

</TestFile> 

私は、XSLTと今まで得たところです:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" indent="yes"/> 

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

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

<xsl:template match="Content"> 
<xsl:copy> 
    <xsl:for-each-group select="node()" group-ending-with="EndUnderline"> 
    <xsl:choose> 
    <xsl:when test="current-grouping-key()"> 
    <xsl:variable name="start" select="current-group()[self::Underline][1]"/> 
     <xsl:copy-of select="current-group()[$start >> .]"/> 
     <u> 
     <xsl:copy-of select="current-group()[. >> $start][not(self::Underline)][not(self::EndUnderline)]"/> 
     </u> 
     </xsl:when> 
    <xsl:otherwise> 
    <xsl:copy-of select="current-group()"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:for-each-group> 
</xsl:copy> 
</xsl:template> 
</xsl:stylesheet> 

そして、これが結果です。

<TestFile> 

<!-- Para tag containing no underline tags --> 
<Para> 
<Content> 
    <u/> 
</Content> 
</Para> 

<!-- correct encapsulation from source --> 
<Para> 
<Content> 
    <u>[text_to_be_underlined]</u> 
    <u/> 
</Content> 
</Para> 

<!-- extra underline tag that should be ignored --> 
<Para> 
<Content> 
    <u>[text_to_be_underlined]</u> 
    <u/> 
</Content> 
</Para> 

<!-- some extra end underline tags that should be ignored --> 
<Para> 
<Content> 
    <u/> 
    <u/> 
</Content> 
</Para> 
</TestFile> 

これは私が目指してる何ですが:

<TestFile> 
<!-- Para tag containing no underline tags --> 
<Para> 
    <Content>[text_not_underlined]</Content> 
</Para> 

<!-- correct encapsulation from source --> 
<Para> 
<Content> 
    <u>[text_to_be_underlined]</u> 
    <p>Some test data</p> 
</Content> 
</Para> 

<!-- extra underline tag that should be ignored --> 
<Para> 
<Content> 
    <u>[text_to_be_underlined]</u> 
    <p>Some other test data</p> 
</Content> 
</Para> 
<!-- some extra end underline tags that should be ignored --> 
<Para> 
<Content> 
    [no_longer_underline] 
    <p>: More data</p> 
</Content> 
</Para> 
</TestFile> 

私は正しい方向に私を指すことができる任意のヒントの事前に感謝!

答えて

0

おかげで、これは実際にのみ動作します。

 <xsl:template match="Content"> 
    <xsl:copy> 
     <xsl:for-each-group select="node()" group-ending-with="EndUnderline"> 
      <xsl:variable name="start" select="current-group()[self::Underline][1]"/> 
      <xsl:choose> 
       <xsl:when test="$start"> 
        <!-- Content element contains at least one <Underline/> marker element, so we group all between the first <Underline/> tag until the first <EndUnderline/> tag --> 
        <xsl:apply-templates select="current-group()[$start >> .]"/> 
        <!-- Every tag before the first <Underline/> marker gets transformed as standard, all tags between the markers gets encapsulated in a <u> tag --> 
        <u> 
         <xsl:apply-templates select="current-group()[. >> $start][not(self::Underline)][not(self::EndUnderline)]"/> 
        </u> 
       </xsl:when> 
       <xsl:otherwise> 
        <!-- Apply standard transformation on current group (not containing underline tags...) --> 
        <xsl:apply-templates select="current-group()"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 
<!-- Get rif of standalone end tags... --> 
<xsl:template match="EndUnderline"/> 

はとにかく、私はいくつかの他の有用なインターネットの人々のおかげでので、私たちは最後に思い付いた共有でき、その間に答えを見つけました

1

これは単純な例であり、私のソリューションはあなたが望むものではないと言います。あなたはこれをにグループ化しないでくださいを試しましたか?次のXSLは正しい結果をもたらすようです。開始タグと私は仮定終了タグの間に単一の要素がある場合

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

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

    <xsl:template match="p"> 
     <xsl:copy-of select="." /> 
    </xsl:template> 

    <xsl:template match="Content/text()"> 
     <xsl:choose> 
     <xsl:when test="preceding-sibling::Underline"></xsl:when> 
     <xsl:when test="following-sibling::EndUnderline"></xsl:when> 
     <xsl:otherwise> 
     <xsl:copy-of select="." /> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template match="Content/Underline" /> 

    <xsl:template match="Content/EndUnderline"> 
     <xsl:choose> 
     <xsl:when test="preceding-sibling::Underline"> 
      <u><xsl:value-of select="preceding-sibling::text()[1]" /></u> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="preceding-sibling::text()[1]" /> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet>