2010-07-12 147 views
1

我在想如果/如何在XSLT中完成以下操作。如果不是,你会用什么? (我用OmniMark,但我想知道这是否可能在XSLT)通过XSLT中的文本处理创建新元素

下面是输入XML的例子:

<?xml version="1.0" encoding="UTF-8"?> 
<fragment> 
    <firstElem> 
     <secondElem>D12</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J7-10</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C2-4</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP20-25</secondElem> 
    </firstElem> 
</fragment> 

我需要什么做的是采取的文本内容secondElem元素并根据需要创建尽可能多的新元素firstElem。 ' - '是一个“通过”,所以'A3J7-10'真的是'A3J7'到'A3J10'(A3J7,A3J8,A3J9,A3J10)。 (有时“通过”将相当大,如A1B2C1-150(A1B2C1到A1B2C150)。)

如果没有短划线,则不需要做任何事情。

下面是输出XML的例子:

<?xml version="1.0" encoding="UTF-8"?> 
<fragment> 
    <firstElem> 
     <secondElem>D12</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J7</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J8</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J9</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J10</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C2</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C3</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C4</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP20</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP21</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP22</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP23</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP24</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP25</secondElem> 
    </firstElem> 
</fragment> 

有没有办法在XSLT做到这一点?

谢谢!

+0

好问题(+1)。请参阅我的答案以获得简短而高效的XSLT 2.0解决方案。 – 2010-07-13 13:32:43

回答

1

下面是一个XSLT 2.0溶液

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

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

<xsl:template match="firstElem[contains(secondElem, '-')]"> 
    <xsl:analyze-string select="secondElem" 
    regex="(^.*[^\d])([\d]*)-([\d]*)"> 

    <xsl:matching-substring> 
     <xsl:variable name="vbaseName" select="regex-group(1)"/> 
     <xsl:variable name="vstart" select="regex-group(2)"/> 
     <xsl:variable name="vend" select="regex-group(3)"/> 

     <xsl:for-each select= 
      "xs:integer($vstart) to xs:integer($vend)"> 
       <firstElem> 
        <secondElem> 
         <xsl:value-of select="concat($vbaseName, .)"/> 
        </secondElem> 
       </firstElem> 
     </xsl:for-each> 
    </xsl:matching-substring> 
    </xsl:analyze-string> 
</xsl:template> 
</xsl:stylesheet> 

当上述变换所提供的XML应用文件

<fragment> 
    <firstElem> 
     <secondElem>D12</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J7-10</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C2-4</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP20-25</secondElem> 
    </firstElem> 
</fragment> 

想要的,正确的结果产生

<fragment> 
    <firstElem> 
     <secondElem>D12</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J7</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J8</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J9</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J10</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C2</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C3</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C4</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP20</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP21</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP22</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP23</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP24</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP25</secondElem> 
    </firstElem> 
</fragment> 

请注意

  1. 使用正则表达式。

  2. 子表达式捕获和regex-group()函数。

  3. 使用<xsl:analyze-string><xsl:matching-substring>

  4. 使用该to操作员来创建序列在<xsl:for-each>

  5. 上的非节点(整数)的序列中使用的<xsl:for-each>使用。

+0

适用于XSLT 2.0解决方案。我想成为XSLT2的家伙,ja! – 2010-07-13 16:11:07

+0

非常感谢。这是我见过的第一个使用过的。这将非常方便。 – 2010-07-13 19:17:17

2

该样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl"> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="firstElem[contains(.,'-')]" name="firstElem"> 
     <xsl:param name="from"> 
      <xsl:call-template name="getfrom"/> 
     </xsl:param> 
     <xsl:param name="base" select="normalize-space(substring-before(.,concat($from,'-')))"/> 
     <xsl:param name="to" select="substring-after(.,'-')"/> 
     <xsl:if test="$to >= $from"> 
      <firstElem> 
       <secondElem> 
        <xsl:value-of select="concat($base,$from)"/> 
       </secondElem> 
      </firstElem> 
      <xsl:call-template name="firstElem"> 
       <xsl:with-param name="from" select="$from + 1"/> 
       <xsl:with-param name="base" select="$base"/> 
       <xsl:with-param name="to" select="$to"/> 
      </xsl:call-template> 
     </xsl:if> 
    </xsl:template> 
    <xsl:template name="getfrom"> 
     <xsl:param name="string" select="substring-before(.,'-')"/> 
     <xsl:variable name="last" select="substring($string,string-length($string))"/> 
     <xsl:if test="contains('',$last)"> 
      <xsl:call-template name="getfrom"> 
       <xsl:with-param name="string" select="substring($string,1,string-length($string)-1)"/> 
      </xsl:call-template> 
      <xsl:value-of select="$last"/> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

输出:

<fragment> 
    <firstElem> 
     <secondElem>D12</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J7</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J8</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J9</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>A3J10</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C2</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C3</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>C4</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP20</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP21</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP22</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP23</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP24</secondElem> 
    </firstElem> 
    <firstElem> 
     <secondElem>QW9R7NP25</secondElem> 
    </firstElem> 
</fragment> 
+0

@Alejandro:非常感谢你的答案! – 2010-07-13 19:18:05