我在将text()中的dumbquotes转换为smartquotes时遇到了这个问题。这是我正在使用的模板:
<xsl:template match="text()">
<xsl:analyze-string regex=""([^"]*)"" select=".">
<xsl:matching-substring>
<xsl:value-of select="replace(., '"([^"]*)"' , '“$1”')"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."></xsl:value-of>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
这适用于以下内容:
<p>“Sachin Tendulkar” is the captain of Mumbai Indians.</p>
但是,当<p>
具有内部子节点时,它会失败。例如:
<p>"Board of control<changedText action="deleted"/><changedText action="added"> for</changedText> Cricket In India" is the national governing body for cricket in India.</p>
在这种情况下,text()在第一个实例中仅包含"Board of control
。由于它没有找到任何结束引号,模板不会将其转换为智能引号。
请帮我修改此模板,以便转换引号以及保留子节点。
答案 0 :(得分:1)
您的评论建议您希望每个段落中的第一个引号成为左侧智能引号,然后在段落的其余部分中替换右侧和左侧引号。
因此,在每个文本节点的开头,您需要确定此段落中在此之前的所有文本节点中是否存在偶数或奇数引号,按顺序要知道你是否在引文的“内部”或“外部”开始此文本节点(即,下一个智能引用应该是正确的还是左引用)。
<xsl:variable name="thisNode" select="." />
<xsl:variable name="inQuotes" select="
sum(for $text in ancestor::p[1]//text()[. << $thisNode]
return string-length(replace($text, '[^"]', ''))) mod 2" />
(ancestor::p[1]//text()[. << $thisNode]
是一个XPath表达式,选择封闭的p
元素的文本节点后代,它们在文档顺序中位于当前元素之前)
一旦你知道这一点,就可以使用while循环风格的递归模板来处理当前的文本节点
<xsl:template name="smartquotes">
<xsl:param name="q" as="xs:string*"/>
<xsl:param name="text" as="xs:string" />
<xsl:choose>
<xsl:when test="contains($text, '"')">
<xsl:value-of select="concat(substring-before($text, '"'), $q[1])" />
<xsl:call-template name="smartquotes">
<xsl:with-param name="q" select="($q[2], $q[1])" />
<xsl:with-param name="text" select="substring-after($text, '"')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
将.
作为text
参数传递,将('“','”')
或('”','“')
传递给q
,具体取决于您当前是$inQuotes
。
这看起来毫无效率(一个天真的实现将是文本节点数量的二次方)但希望XSLT处理器能够通过缓存每个节点的string-length(replace($text, '[^"]', ''))
值进行优化。