问题
i need to find and replace an entity in xslt. i need to do this without using template match.
suppose my xml like this,
<root>
<p>Master's</p>
<p><blockFixed type="quotation"><p>let's</p></blockFixed></p>
<p>student's<featureFixed id=1/></p>
<p><blockFixed type="quotation"><p>nurse's</p></blockFixed></p>
<p>Master's</p>
</root>
i need to change '
into ’
so output should be like this,
<root>
<p>Master<apos>’</apos>s</p>
<p><blockFixed type="quotation"><p>let<apos>’</apos>s</p></blockFixed></p>
<p>student<apos>’</apos>s<featureFixed id=1/><\p>
<p><blockFixed type="quotation"><p>nurse<apos>’</apos>s</p></blockFixed></p>
<p>Master's</p>
</root>
i used the replace method by using template match p
but after that i can not able to do any operation on other tags like blockfixed
etc,. so pls suggest simple xslt to do this.
i used the following xslt,
<xsl:template match="p">
<xsl:copy>
<xsl:apply-templates select="current()/node()" mode="replace"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="replace">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="from">'</xsl:with-param>
<xsl:with-param name="to" select="'’'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains($text, $from)">
<xsl:variable name="before" select="substring-before($text, $from)"/>
<xsl:variable name="after" select="substring-after($text, $from)"/>
<xsl:variable name="prefix" select="concat($before, $to)"/>
<xsl:copy-of select="$before"/>
<Apos>
<xsl:copy-of select="$to"/>
</Apos>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
thanks in advance.
回答1:
The problem is with your template matching the p element
<xsl:template match="p">
<xsl:copy>
<xsl:apply-templates select="current()/node()" mode="replace"/>
</xsl:copy>
</xsl:template>
In particular, you use of mode. Although you are selecting all child nodes of the p element, you have only provided a matching template for text() nodes with a mode of replace. This means all other elements won't get picked out, and so blockFixed is ignored.
Instead, remove the above template matching p from your XSLT, and replace the following line:
<xsl:template match="text()" mode="replace">
With this one
<xsl:template match="p/text()">
This assumes you building upon the identity transform in your XSLT. Here is the abridged version of the XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p/text()">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="from">'</xsl:with-param>
<xsl:with-param name="to" select="'&rsquo;'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains($text, $from)">
<xsl:variable name="before" select="substring-before($text, $from)"/>
<xsl:variable name="after" select="substring-after($text, $from)"/>
<xsl:variable name="prefix" select="concat($before, $to)"/>
<xsl:copy-of select="$before"/>
<Apos>
<xsl:value-of select="$to" disable-output-escaping="yes"/>
</Apos>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
回答2:
You mention the replace
method which is only available in XSLT and XPath 2.0 so I assume that you use an XSLT 2.0 processor? And are you aware that XSLT operates on a data model with plain text nodes with Unicode string values so entity reference are not modeled in that data model. And to enforce a character in the transformation result to be output as an entity reference instead of as a Unicode character you would need to XSLT 2.0 character maps.
So what you can do is process text nodes with analyze-string e.g.
<xsl:template match="p//text()">
<xsl:analyze-string select="." regex="'">
<xsl:matching-substring>
<apos>’</apos>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
to output an apos
element with that right quote character ’
, then you would need to add a character map that ensures such a character is replaced with its entity reference.
And I realize I used a template to solve that, in spite of your request. But all you need to incorporate my suggestion into a more complex stylesheet is doing apply-templates
in a template for p
elements, so maybe you can do that.
来源:https://stackoverflow.com/questions/11503644/find-and-replace-entity-in-xslt