我正在尝试编写一个模板,该模板将在父元素中抓取文本节点和元素的混合,并创建一个新节点。我做了很多搜索,找不到我想要的东西......所以希望我不是要问基本问题。
以下是我要转换的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中可能会变得奇怪。
之前有人遇到过这种情况吗? 谢谢, 杰森
任何想法
答案 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>