xml文档的作者并未将元素中的所有文本都包含在内,这些元素将被转换为超链接。我想处理或预处理xml以包括必要的文本。我发现这很难描述,但是一个简单的例子应该可以说明我的尝试。 我正在使用XSLT 2.0。我已经针对各种情况进行了正则表达式处理,但无法弄清楚。
我知道如何使用perl / python正则表达式执行此操作,但是我不知道如何使用XSLT进行处理。
这是作者的“非常”简化的xml,在其中他们从glink元素中省略了“(第3页)”。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<para>
Go look at figure <glink refid=1>Figure 22</glink> (Sheet 3). Then go do something else.
</para>
</root>
这是我希望将其转换为glink标记中现在的“(第3张)”的地方:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<para>
Go look at figure <glink refid=1>Figure 22 (Sheet 3)</glink>. Then go do something else.
</para>
</root>
应进行此转换的情况是,在紧随其后的glink元素(此正则表达式):
\s\(Sheet \d\)
我目前有2个XSLT。第一个预处理XML以转换许多其他情况(使用正则表达式/ xsl:analyze-string)。从预处理的xml转换为HTML的第二个XSLT。第二个XSLT具有处理glink元素并将其转换为超链接的模板,但是该超链接应包括Sheet信息。
我认为先对其进行预处理,而将第二个XSLT保留下来比较容易,但是我总是欣赏更好的方法。
谢谢您的宝贵时间。
答案 0 :(得分:1)
现有答案具有正确的方法,但我会加强正则表达式模式和匹配模式:
<xsl:param name="pattern" as="xs:string">\s\(Sheet \d\)</xsl:param>
<xsl:variable name="pattern2" as="xs:string" select="'^' || $pattern"/>
<xsl:variable name="pattern3" as="xs:string" select="'^(' || $pattern || ')(.*)'"/>
<xsl:template match="glink[@refid][following-sibling::node()[1][self::text()[matches(., $pattern2)]]]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:value-of select=". || replace(following-sibling::node()[1], $pattern3, '$1', 's')"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()[preceding-sibling::node()[1][self::glink[@refid]]][matches(., $pattern2)]">
<xsl:value-of select="replace(., $pattern3, '$2', 's')"/>
</xsl:template>
https://xsltfiddle.liberty-development.net/bFN1y9z/1
否则,我认为匹配和替换发生的次数多于glink
之后(直接?)之后的模式,如您在https://xsltfiddle.liberty-development.net/bFN1y9z/2中所见。
我发布的代码使用XPath 3.1的||
字符串连接运算符,但是如果目标是XSLT 2处理器,那么当然可以用普通的concat
函数调用来代替。
答案 1 :(得分:1)
为了减少使用正则表达式功能,我将使用以下方法:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="glink">
<xsl:variable name="vAnalyzedString">
<xsl:analyze-string
select="following-sibling::node()[1][self::text()]"
regex="^\s*\(Sheet\s+\d+\)">
<xsl:matching-substring>
<match>
<xsl:value-of select="."/>
</match>
</xsl:matching-substring>
<xsl:non-matching-substring>
<no-match>
<xsl:value-of select="."/>
</no-match>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<xsl:apply-templates
select="$vAnalyzedString/match/text()"/>
</xsl:copy>
<xsl:apply-templates
select="$vAnalyzedString/no-match/text()"/>
</xsl:template>
<xsl:template match="text()[preceding-sibling::node()[1][self::glink]]"/>
</xsl:stylesheet>
输出:
<root>
<para>
Go look at figure <glink refid="1">Figure 22 (Sheet 3)</glink>. Then go do something else.
</para>
</root>
请注意:已处理所有glink
,但这些文本节点都不是第一个兄弟姐妹。可以使用xsl:analize-string
指令,但是您将需要声明一个带有部分结果的变量,然后对这些结果进行导航。另外,这种方法可以轻松地让您进一步处理那些(现在)文本节点,并且它仅一个正则表达式处理。
答案 2 :(得分:0)
您可以将这两个模板与身份模板结合使用:
<xsl:template match="glink">
<xsl:copy>
<xsl:copy-of select="@*|text()" />
<xsl:text> </xsl:text>
<xsl:value-of select="normalize-space(replace(following::text()[1],'\s(\(Sheet \d\)).*',' $1'))" />
</xsl:copy>
</xsl:template>
<xsl:template match="text()[preceding-sibling::glink]">
<xsl:value-of select="normalize-space(replace(.,'\s\(Sheet \d\)(.*)',' $1'))" />
</xsl:template>
第一个将(Sheet 3)
字符串包含到glink
中,第二个将(Sheet 3)
从随后的text()
节点中排除。
结果是:
<root>
<para>
Go look at figure <glink refid="1">Figure 22 (Sheet 3)</glink>. Then go do something else.</para>
</root>