2016-08-24 103 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>