如何在XSLT2 replace()函数中“混合和匹配”实体转换?

时间:2012-01-18 09:24:42

标签: xml xslt xslt-2.0

我正在使用基于this答案的样式表来试验XSLT2:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>
 <xsl:template match="source/text()">
  <xsl:sequence select="replace(., '&lt;.*?&gt;', '<ph>$0</ph>')"/>
 </xsl:template>
</xsl:stylesheet>

旨在进行多次替换,例如:

<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns:xliff="urn:oasis:names:tc:xliff:document:1.1" version="1.1">
  <file>
    <source>abc &lt;field1&gt; def &lt;field2&gt; ghi</source>
  </file>
</xliff>

为:

<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns:xliff="urn:oasis:names:tc:xliff:document:1.1" version="1.1">
  <file>
    <source>abc <ph>&lt;field1&gt;</ph> def <ph>&lt;field2&gt;</ph> ghi</source>
  </file>
</xliff>

但是我的转换无效,我收到此错误:

Error on line 12 column 54 of my.xsl:
  SXXP0003: Error reported by XML parser: The value of attribute "select" associated with an
  element type "null" must not contain the '<' character.

如果我使用select="replace(., '&lt;(.*?)&gt;', '&lt;ph&gt;F&lt;/phgt;')",那么我会在输出中获得...&lt;ph&gt;...

如果我使用DOE我会引入其他问题,因为我可能还有其他实体,我想保持不变。如果我使用<xsl:output method="text"/>我丢失了大部分xml - 还有其他一些“混合和匹配”的方式吗?

2 个答案:

答案 0 :(得分:4)

问题在于

<xsl:sequence select="replace(., '&lt;(.*?)&gt;', '<ph>F</ph>')"/>

格式良好的XML文档不能在属性值中包含<字符

在这种特殊情况下,上面的select属性包含子字符串<ph>F</ph>,这会导致样式表甚至不被解析为XML文档。

更重要的是,元素不能仅通过字符串替换生成 - 结果将只是字符串(包含编码元素表示) - 而不是元素。

以下是如何实现您的目标

     

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

 <xsl:template match="source/text()">
  <xsl:analyze-string select="." regex="&lt;(.*?)&gt;">
    <xsl:matching-substring>
      <ph><xsl:value-of select="regex-group(1)"/></ph>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
     <xsl:sequence select="."/>
    </xsl:non-matching-substring>
  </xsl:analyze-string>
 </xsl:template>

将此转换应用于提供的XML文档

<xliff xmlns:xliff="urn:oasis:names:tc:xliff:document:1.1" version="1.1">
    <file>
        <source>abc &lt;field1&gt; def &lt;field2&gt; ghi</source>
    </file>
</xliff>

生成了想要的结果

<xliff xmlns:xliff="urn:oasis:names:tc:xliff:document:1.1" version="1.1">
      <file>
            <source>abc <ph>field1</ph> def <ph>field2</ph> ghi</source>
      </file>
</xliff>

解释:正确使用XSLT 2.0说明 <xsl:analyze-string> <xsl:matching-substring> {{ 3}} <xsl:non-matching-substring>

答案 1 :(得分:1)

如果源文档中出现字符串&lt;,则文档的XDM树表示将包含字符'&lt;'在它的位置,它将匹配正则表达式'&lt;',它在样式表中写为&lt;

所以它应该有效,但你显然做错了什么。告诉我们你做了什么,我们可能有机会告诉你哪里出错了。如果你不告诉我们问题是什么,告诉我们你遇到问题没什么用处。