xslt:从父元素中的混合内容创建新节点

时间:2010-09-09 23:31:30

标签: xslt

我正在尝试编写一个模板,该模板将在父元素中抓取文本节点和元素的混合,并创建一个新节点。我做了很多搜索,找不到我想要的东西......所以希望我不是要问基本问题。

以下是我要转换的xml示例:

<?xml version="1.0"?>
<root>
 <para>Here is some text that will ask users to enter a <rule-line/> [<emph type="it">date</emph>], and maybe their <rule-line/> [<emph type="it">name</emph>]. The text could come in different [<emph type="it">order</emph>] <rule-line/>, and their could be any number of instances.</para>

</root>

我想将括号内的文本和规则分组到一个新元素中,如下所示:

<entry>[<emph type"it">date</emph>]</entry>

我有一个模板可以识别我想要更改的文本,我可以更改它,但我不知道如何将我想要的文本添加到结果树中并省略旧文本。

以下是相关模板:

<xsl:template match="para">
 <xsl:for-each select="* | text()">
  <xsl:choose>

   <xsl:when test="self::rule-line and following-sibling::node()[1][starts-with(., ' [')] and string(node-name(following-sibling::node()[2])) = 'emph' and following-sibling::node()[3][starts-with(., ']')]">
    <xsl:comment>made match</xsl:comment>
    <xsl:call-template name="codeEntry">
     <xsl:with-param name="rule" select="."/>
     <xsl:with-param name="openBracket" select="following-sibling::node()[1]"/>
     <xsl:with-param name="emphTag" select="following-sibling::node()[2]"/>
     <xsl:with-param name="closeBracketString" select="following-sibling::node()[3]"/>
    </xsl:call-template>
   </xsl:when>
   <xsl:otherwise>
    <xsl:copy-of select="."/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:for-each>

</xsl:template>


<xsl:template name="codeEntry">
<xsl:param name="rule"/>
<xsl:param name="openBracket"/>
<xsl:param name="emphTag"/>
<xsl:param name="closeBracketString"/>
<entry>
<xsl:copy-of select="$openBracket"/>
<xsl:copy-of select="$emphTag"/>
<xsl:text>] </xsl:text>
</entry>
<xsl:value-of select="substring-after($closeBracketString, ']')"/>

</xsl:template>

显然,when语句抓取一组节点,但是当每个节点通过否则块时,它会被复制到结果树中。我不确定如何处理这个,因为para可以以任何顺序包含任意数量的这些节点分组,或者没有。 (一旦我想出这个,我会在规则之前处理括号内文本的块时添加另一个)

我认为创建一个告诉模板忽略节点的变量是要走的路......但我对不可变变量及其范围有点模糊......

我还试图想出一种我可以尝试递归执行此操作的方法......但这需要在一个点添加一个开始标记,在另一个点添加结束标记,或者如果正在处理的节点在序列的中间...我知道在xslt中可能会变得奇怪。

之前有人遇到过这种情况吗? 谢谢, 杰森

任何想法

1 个答案:

答案 0 :(得分:1)

只是为了好玩(模式多么糟糕!),这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="rule-line"/>
    <xsl:template match="emph">
        <entry>
            <xsl:text>[</xsl:text>
            <xsl:call-template name="identity"/>
            <xsl:text>]</xsl:text>
        </entry>
    </xsl:template>
    <xsl:template match="text()[normalize-space()='[']
                               [following-sibling::*[1][self::emph]] |
                         text()[normalize-space()=']']
                               [preceding-sibling::*[1][self::emph]]"
                  priority="1"/>
    <xsl:template match="text()[starts-with(normalize-space(),']')]
                               [preceding-sibling::*[1][self::emph]]">
        <xsl:value-of select="substring-after(.,']')"/>
    </xsl:template>
    <xsl:template match="text()[substring(normalize-space(),
                                          string-length(normalize-space()),
                                          1) = '[']
                               [following-sibling::*[1][self::emph]]">
        <xsl:call-template name="crop-both">
            <xsl:with-param name="pString" select="concat(']',.)"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template match="text()[starts-with(normalize-space(),']')]
                               [substring(normalize-space(),
                                          string-length(normalize-space()),
                                          1) = '[']
                               [preceding-sibling::*[1][self::emph]]
                               [following-sibling::*[1][self::emph]]"
                  priority="1" name="crop-both">
        <xsl:param name="pString" select="."/>
        <xsl:variable name="vReverse">
            <xsl:call-template name="reverse">
                <xsl:with-param name="pString" 
                                select="substring-after(.,']')"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:call-template name="reverse">
            <xsl:with-param name="pString"
                            select="substring-after($vReverse,'[')"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template name="reverse">
        <xsl:param name="pString"/>
        <xsl:if test="$pString!=''">
            <xsl:call-template name="reverse">
                <xsl:with-param name="pString"
                                select="substring($pString,2)"/>
            </xsl:call-template>
            <xsl:value-of select="substring($pString,1,1)"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

输出:

<root>
<para>Here is some text that will ask users to enter a <entry>[<emph type="it">date</emph>]</entry>, and maybe their <entry>[<emph type="it">name</emph>]</entry>. The text could come in different <entry>[<emph type="it">order</emph>]</entry>, and their could be any number of instances.</para>
</root>