XSL Replace()函数去除了标记

时间:2018-02-07 21:53:16

标签: xml xslt saxon

我试图在html文档中转义来自用户输入的引号,但是当我使用它时,replace()函数正在删除标记。为什么呢?

I.e从XSL下面的代码中,如果我改变了这一行:

<xsl:copy-of select="replace($s, '&quot;', '\\&quot;')" />

<xsl:copy-of select="$s" />

它有效,但显然没有做我需要的报价转义。或者你有任何其他方法来逃避报价。

PS:我需要转义,因为我将值传递给带有c#的后端变量,如果我没有转义它,则代码会刹车。

XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template name="encode-string">
  <xsl:param name="s" select="@* | node()"/>
  <xsl:copy-of select="replace($s, '&quot;', '\\&quot;')" />
</xsl:template>
<xsl:template match="/">
  <xsl:call-template name="encode-string">
    <xsl:with-param name="s" >
      <xsl:copy-of select="Contact/node()"/>
    </xsl:with-param> 
</xsl:call-template>
</xsl:template>

HTML

<Contact> 
<MobileNumber>0123456789</MobileNumber>
<Email type="new">johndoe@coldmail.com</Email>
<Address type="red">Antartica"s drive 41</Address>
</Contact>

我需要转义所有节点的内容。也就是说,所有内容都需要被视为一个单独的字符串。类似于序列化的东西,但它也应该包括子节点属性。 (一切)

想要的结果:

<MobileNumber>0123456789</MobileNumber><Email type=\"new\">johndoe@coldmail.com</Email> <Address type=\"red\">Antartica\"s drive 41</Address>

这样我就可以将它传递给C#变量:

string content = "<MobileNumber>0123456789</MobileNumber><Email type=\"new\">johndoe@coldmail.com</Email> <Address type=\"red\">Antartica\"s drive 41</Address>";

3 个答案:

答案 0 :(得分:0)

replace()函数将字符串作为输入并返回一个字符串,因此它不会按照您的意图执行。

如果要全局替换字符,请考虑使用character-map ...

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" use-character-maps="encode"/>
  <xsl:strip-space elements="*"/>

  <xsl:character-map name="encode">
    <xsl:output-character character="&quot;" string="&amp;quot;"/>
  </xsl:character-map>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

完整的工作示例:http://xsltfiddle.liberty-development.net/gWcDMen

答案 1 :(得分:0)

XSLT不对包含标记的词法字符串进行操作,它在节点树上运行。因此,您对replace()函数删除标记的陈述表明您还没有真正获得XSLT如何工作的正确概念模型。除非你解决这个问题,否则你会遇到更多这样的问题。

如果提供节点作为需要字符串的函数(如replace())的输入,则处理器将提取节点的字符串值,该节点是节点的所有文本节点后代的串联。您可以将其视为&#34;删除标记&#34;如果你愿意,但它并不是一个准确的描述。

解决此问题的最佳方法是将replace函数分别应用于每个后代文本节点。在XSLT 3.0中,您可以这样做:

<xsl:mode name="escape-quotes" on-no-match="shallow-copy"/>
<xsl:template match="text()" mode="escape-quotes">
  <xsl:value-of select="replace(.....)"/>
</xsl:template>

然后将xsl:copy-of替换为xsl:apply-templates mode="escape-quotes"。在早期的XSLT版本中,您需要拼出&#34;浅拷贝&#34;模板规则全部。

答案 2 :(得分:0)

@Martin Honnen通过此解决方案的链接提供了我在问题评论中所需的确切内容http://xsltfiddle.liberty-development.net/pPgCcot 通过在替换呼叫之前简单地使用serilize:

  <xsl:template match="Contact">
       <xsl:value-of select="replace(serialize(*), '&quot;', '\\&quot;')"/>
  </xsl:template>