2010-07-12 148 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