У меня есть проблема, которая, как мне кажется, связана с пространством имен при использовании функции замены строки exslt. Я хочу заменить несколько строк в целевой строке, используя форму набора узлов функции замены строки exslt в соответствии с документацией здесь. Однако, похоже, он заменяет только первую строку набора узлов, а не другие.
Вот мой файл:
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
<!ENTITY yen "¥">
<!ENTITY circle "●">
<!ENTITY raquo "»">
]>
<xsl:stylesheet
version="1.0"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:str="http://exslt.org/strings"
xmlns:exsl="http://exslt.org/common"
xmlns:regexp="http://exslt.org/regular-expressions"
extension-element-prefixes="msxsl str exsl regexp">
<xsl:output
method="html"
indent="yes"
encoding="utf-8"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
/>
<!-- Start of the main template -->
<xsl:template match="/Top">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
<body>
<xsl:variable name="text">
-[this]- This is a test string -[that]-
-[this]- This is another test string -[that]-
</xsl:variable>
text: <xsl:value-of select="$text" disable-output-escaping="yes" />
<xsl:variable name="searches" xmlns="">
<replacements xmlns="">
<searches>
<search>-[this]-</search>
<search>-[that]-</search>
</searches>
<replaces>
<replace>**[this]**</replace>
<replace>**[that]**</replace>
</replaces>
</replacements>
</xsl:variable>
<xsl:variable name="search_set" select="exsl:node-set($searches)/replacements/searches/search" />
<xsl:variable name="replace_set" select="exsl:node-set($searches)/replacements/replaces/replace" />
search_set: <xsl:copy-of select="$search_set" />
replace_set: <xsl:copy-of select="$replace_set" />
<xsl:if test="$search_set">
replaced via function:
<xsl:value-of select="str:replace($text, $search_set, $replace_set)" disable-output-escaping="yes" />
replaced via template:
<xsl:variable name="replaced_tpl">
<xsl:call-template name="str:replace">
<xsl:with-param name="string" select="$text"/>
<xsl:with-param name="search" select="$search_set"/>
<xsl:with-param name="replace" select="$replace_set"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$replaced_tpl" disable-output-escaping="yes" />
</xsl:if>
</body>
</html>
</xsl:template><!-- / end main template -->
<xsl:template name="str:replace" xmlns="">
<xsl:param name="string" select="''" />
<xsl:param name="search" select="/.." />
<xsl:param name="replace" select="/.." />
<xsl:choose>
<xsl:when test="not($string)" />
<xsl:when test="not($search)">
<xsl:value-of select="$string" />
</xsl:when>
<xsl:when test="function-available('exsl:node-set')">
<!-- this converts the search and replace arguments to node sets
if they are one of the other XPath types -->
<xsl:variable name="search-nodes-rtf">
<xsl:copy-of select="$search" />
</xsl:variable>
<xsl:variable name="replace-nodes-rtf">
<xsl:copy-of select="$replace" />
</xsl:variable>
<xsl:variable name="replacements-rtf">
<xsl:for-each select="exsl:node-set($search-nodes-rtf)/node()">
<xsl:variable name="pos"
select="position()" />
<replace search="{.}">
<xsl:copy-of select="exsl:node-set($replace-nodes-rtf)/node()[$pos]" />
</replace>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="sorted-replacements-rtf">
<xsl:for-each select="exsl:node-set($replacements-rtf)/replace">
<xsl:sort select="string-length(@search)"
data-type="number"
order="descending" />
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:variable>
<xsl:call-template name="str:_replace">
<xsl:with-param name="string"
select="$string" />
<xsl:with-param name="replacements"
select="exsl:node-set($sorted-replacements-rtf)/replace" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">
ERROR: template implementation of str:replace relies on exsl:node-set().
</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="str:_replace">
<xsl:param name="string"
select="''" />
<xsl:param name="replacements"
select="/.." />
<xsl:choose>
<xsl:when test="not($string)" />
<xsl:when test="not($replacements)">
<xsl:value-of select="$string" />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="replacement"
select="$replacements[1]" />
<xsl:variable name="search"
select="$replacement/@search" />
<xsl:choose>
<xsl:when test="not(string($search))">
<xsl:value-of select="substring($string, 1, 1)" />
<xsl:copy-of select="$replacement/node()" />
<xsl:call-template name="str:_replace">
<xsl:with-param name="string"
select="substring($string, 2)" />
<xsl:with-param name="replacements"
select="$replacements" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($string, $search)">
<xsl:call-template name="str:_replace">
<xsl:with-param name="string"
select="substring-before($string, $search)" />
<xsl:with-param name="replacements"
select="$replacements[position() > 1]" />
</xsl:call-template>
<xsl:copy-of select="$replacement/node()" />
<xsl:call-template name="str:_replace">
<xsl:with-param name="string"
select="substring-after($string, $search)" />
<xsl:with-param name="replacements"
select="$replacements" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="str:_replace">
<xsl:with-param name="string"
select="$string" />
<xsl:with-param name="replacements"
select="$replacements[position() > 1]" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
И вот результат:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml"><head><style type="text/css"></style></head><body>
text:
-[this]- This is a test string -[that]-
-[this]- This is another test string -[that]-
search_set: <search xmlns="">-[this]-</search><search xmlns="">-[that]-</search>
replace_set: <replace xmlns="">**[this]**</replace><replace xmlns="">**[that]**</replace>
replaced via function:
**[this]** This is a test string -[that]-
**[this]** This is another test string -[that]-
replaced via template:
**[this]** This is a test string **[that]**
**[this]** This is another test string **[that]**
</body></html>
Как вы можете видеть на выходе. При использовании функции заменяется только строка первого узла. Второй нет. Как видите, я скопировал код шаблона с exslt.org в файл, и сначала он не работал, пока я не добавил xmlns=""
в шаблон str:replace следующим образом:
<xsl:template name="str:replace" xmlns="">
В этот момент форма шаблона работает, что наводит меня на мысль, что это проблема пространства имен. Я считаю, что в функции, когда она сортирует узлы и создает свои собственные узлы replace
, например:
<replace search="{.}">
<xsl:copy-of select="exsl:node-set($replace-nodes-rtf)/node()[$pos]" />
</replace>
Этот узел может оказаться в другом пространстве имен, поэтому последующий цикл не может их адресовать. Добавление атрибута xmlns
к str:replace
помещает все узлы, созданные в нем, в то же нулевое пространство имен, что и узлы, которые я передаю, и тогда это работает. Однако, что бы я ни пытался, я не могу заставить работать версию функции. Я даже удалил все пространства имен из файла и созданного набора узлов xml, и все равно это не работает. Честно говоря, все эти пространства имен меня немного сбивают с толку. Может быть, проблема даже вовсе не в этом.
Любая помощь будет принята с благодарностью, спасибо!
replace
, кажется, помещает их в пространство имен, которое он не может позже читать. - person ragamufin   schedule 26.09.2014