2016-08-24 102 views
0

我正面臨以下XSL轉換的情況。XSL,標記之間的匹配元素

我有這樣的:

<content> 
    xml_and_text_0 
    <break/> 
    xml_and_text_1 
    <break/> 
    ... 
    <break/> 
    xml_and_text_n 
</content> 

我想使用XSL 2.0把上面的XML到這一點:

<content> 
    <block> 
    xml_and_text_0 
    </block> 
    <block> 
    xml_and_text_1 
    </block> 
    ... 
    <block> 
    xml_and_text_n 
    </block> 
</content> 

(我也想some_xml_and_text_k忽略= '',但現在讓我們假設它們是非空的)

我在想我可以使用類似於[XPath : select all following siblings until another sibling的方法,但也許有一個更簡單的方法(或更簡單的XPath表達式)。例如,是否有可能在for-each循環中匹配當前項目之後/之前的所有同胞?

編輯:注意xml_and_text_i是文本和XML的混合,類似於XHTML,我想內包裝,所以像:

<break/> 
this is an <ref id = "123">example</ref>, which is really <citation>awesome</citation> 
<break/> 

將成爲:

<block>this is an <ref id = "123">example</ref>, which is really <citation>awesome</citation></block> 

回答

2

你的問題很混亂。如果您的真實輸入包含元素文本節點之間的break節點,那麼您的示例應該如此。

顯然,這個問題是關於分組和使用XSLT 2.0它可以很容易地解決如:

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

<xsl:template match="/content"> 
    <xsl:copy> 
     <xsl:for-each-group select="node()" group-starting-with="break"> 
      <block> 
       <xsl:copy-of select="current-group()[not(self::break)]" /> 
      </block> 
     </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 
+0

我不這麼認爲。我需要每塊有一個新塊,並且xml_and_text_i包含xml和文本,我想要在內複製該文本。更確切地說,它包含一段標記語言的段落,類似於xhtml,因此您可以閱讀如下內容:「這是一個示例,這真的是真棒」。 – zakmck

+0

@zakmck請編輯您的問題,並顯示上述樣式表無法正確處理的示例輸入。同時說明如果使用XSLT 1.0或2.0。 –

+0

在這個例子中: ' 某些文本 ,這是一示例,這是非常真棒 一些其他文本 ' 你的XSL收率: ' 一些文本 這是一個 ,這是非常 一些其他文本 ' 但我期望: ' \t 某些文本 \t ,這是一示例 ,這真的是真棒 \t 其他一些文字 ' – zakmck

0

感謝michael.hor257k您的解決方案(和混亂抱歉)。您的方法似乎比我的更清晰,如下所示,並基於XSL軸。我的版本也考慮了邊緣情況,但我想你的方法也可以適用於做同樣的事情,我會研究它。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" 
    version="2.0"> 

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

    <xsl:template match="/content"> 
     <content> 

      <xsl:choose> 

       <!-- First of all, distinguish the case where there is at least one separator, from the ones with no separator at all --> 

       <xsl:when test="break"> 
        <xsl:for-each select="break"> 

         <!-- What do we have before the first separator? Create a block only if non-empty stuff --> 
         <xsl:if test="position() = 1"> 
          <xsl:variable name="first_block"><xsl:copy-of select="preceding-sibling::node()" /></xsl:variable> 
          <xsl:if test = "normalize-space ($first_block) != ''" > 
           <xsl:message select="concat ('1|', $first_block, '|')" /> 
           <block id = "{@id}"><xsl:copy-of select="$first_block" /></block> 
          </xsl:if> 
         </xsl:if> 

         <!-- What do we have after the next separator and before the next (or the end)? --> 
         <xsl:variable name="block_content"> 
          <xsl:choose> 
           <xsl:when test="following-sibling::break"> 
            <!-- select all that comes after current node and precedes the next separator --> 
            <xsl:copy-of select="following-sibling::node() intersect following-sibling::break[1]/preceding-sibling::node()" /> 
           </xsl:when> 
           <xsl:otherwise> 
            <!-- One separator after another, without anything in between --> 
            <xsl:copy-of select="following-sibling::node()" /> 
           </xsl:otherwise> 
          </xsl:choose>       
         </xsl:variable> 

         <xsl:message select="concat ('|', $block_content, '|')" /> 
         <xsl:message select="concat ('_|', normalize-space ($block_content), '|_')" /> 

         <!-- Did we get something after the current separator? Create a block if yes --> 
         <xsl:if test = "normalize-space($block_content) != ''"> 
          <block id = "{@id}"><xsl:copy-of select="$block_content" /></block> 
         </xsl:if>      
        </xsl:for-each> 
       </xsl:when> 

       <!-- When some content is available without any separator, create a virtual single block to represent it --> 
       <xsl:otherwise> 
        <xsl:variable name="single_block"><xsl:copy-of select="node()" /></xsl:variable> 
        <xsl:if test = "normalize-space($single_block) != ''"> 
         <block id = "00"><xsl:copy-of select = "$single_block" /></block> 
        </xsl:if> 
       </xsl:otherwise> 
      </xsl:choose> 

     </content> 

    </xsl:template> 

</xsl:stylesheet> 

鑑於此輸入:

<content> 
    Some <b>text</b> 
    <break id = '1'/> 
    this is an <ref id = "123">example</ref>, which is really <citation>awesome</citation> 
    <break id = '2'/> 
    Some other text 
</content> 

它生成的輸出:

<?xml version="1.0" encoding="UTF-8"?> 
<content> 
    <block id="1"> Some <b>text</b></block> 
    <block id="1"> this is an <ref id="123">example</ref>, which is really<citation>awesome</citation></block> 
    <block id="2"> Some other text </block> 
</content>