如何为一个节点使用两个不同的分析字符串

时间:2012-05-20 22:12:49

标签: xml regex xslt

在我的XSLT转换中,我有两个需要用来处理一个节点的分析字符串。它们一个接一个地工作正常,但我不知道如何将它们组合在一起。

XML文档如下所示:

<article>
    <title>Article 1</title>
    <text><![CDATA[Lorem ipsum dolor sit amet, s consectetur adipiscing elit. Donec lorem diam, eleifend sed mollis id, condimentum in velit.

Sed sit amet erat ac mauris adipiscing elementum. Pellentesque eget quam augue, id faucibus magna.

Ut malesuada arcu eu elit sodales sodales. Morbi tristique porttitor tristique. Praesent eget vulputate dui. Cras ut tortor massa, at faucibus ligula.]]></text>
</article>

这是我的XSLT:

<xsl:template match="/">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <title>Page title</title>
        </head>
        <body>
            <xsl:for-each select="article">
                <h1><xsl:value-of select="./title"/></h1>

                <!-- This adds paragraphs tags instead of empty lines in the text -->
                <xsl:analyze-string select="./text" regex="&#xa;">
                    <xsl:non-matching-substring>
                        <p>
                            <xsl:value-of select="." disable-output-escaping="yes"/>
                        </p>
                    </xsl:non-matching-substring>
                </xsl:analyze-string> 

                <!-- This is Czech language specific. It looks for ' s ' (or other letter) and changes second space for &nbsp;. So after that it is ' s&nbsp;'. -->
                <xsl:analyze-string select="./text" regex="(\s[k/K/s/S/v/V/z/Z]\s)">
                    <xsl:matching-substring>
                        <xsl:text> </xsl:text>
                        <xsl:value-of select="replace(., ' ','')" disable-output-escaping="yes"/>
                        <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
                    </xsl:matching-substring>
                    <xsl:non-matching-substring>
                        <xsl:value-of select="." disable-output-escaping="yes"/>
                    </xsl:non-matching-substring>
                </xsl:analyze-string>
            </xsl:for-each>
        </body>
    </html>
</xsl:template>

我需要在生成的文本上应用两个分析字符串,因此段落有<p>个标记,并且在正确的位置添加了&nbsp;

我想要的输出如下:

<h1>Article 1</h1>    
<p>Lorem ipsum dolor sit amet, s&nbsp;consectetur adipiscing elit. Donec lorem diam, eleifend sed mollis id, condimentum in velit.</p>
<p>Sed sit amet erat ac mauris adipiscing elementum. Pellentesque eget quam augue, id faucibus magna.</p>
<p>Ut malesuada arcu eu elit sodales sodales. Morbi tristique porttitor tristique. Praesent eget vulputate dui. Cras ut tortor massa, at faucibus ligula.</p>

知道怎么做吗?感谢您抽出宝贵时间并试图帮助我。

3 个答案:

答案 0 :(得分:3)

此转化

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes" encoding="ascii"/>

 <xsl:template match="/*/text">
  <xsl:analyze-string select=
   "replace(., '\ss\s', ' s&#xA0;')"
   regex="&#xA;">
    <xsl:non-matching-substring>
     <p><xsl:sequence select="."/></p>
    </xsl:non-matching-substring>
  </xsl:analyze-string>
 </xsl:template>

 <xsl:template match="title">
  <h1><xsl:value-of select="."/></h1>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<article>
  <title>Article 1</title>
<text><![CDATA[Lorem ipsum dolor sit amet, s consectetur adipiscing elit. Donec lorem diam, eleifend sed mollis id, condimentum in velit.
Sed sit amet erat ac mauris adipiscing elementum. Pellentesque eget quam augue, id faucibus magna.
Ut malesuada arcu eu elit sodales sodales. Morbi tristique porttitor tristique. Praesent eget vulputate dui. Cras ut tortor massa, at faucibus ligula.]]></text>
</article>

会产生想要的正确结果:

  <h1>Article 1</h1>
<p>Lorem ipsum dolor sit amet, s&#160;consectetur adipiscing elit. Donec lorem diam, eleifend sed mollis id, condimentum in velit.</p>
<p>Sed sit amet erat ac mauris adipiscing elementum. Pellentesque eget quam augue, id faucibus magna.</p>
<p>Ut malesuada arcu eu elit sodales sodales. Morbi tristique porttitor tristique. Praesent eget vulputate dui. Cras ut tortor massa, at faucibus ligula.</p>

注意:不鼓励程序员使用DOE,因为它不是XSLT 2.0的强制功能,并且不保证任何XSLT 2.0处理器都可能支持DOE。要使用的功能是 character maps

然后整个转换变为

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"
  encoding="ascii" use-character-maps="nbsp"/>

 <xsl:character-map name="nbsp">
  <xsl:output-character
  character="&#xA0;" string="&amp;nbsp;"/>
 </xsl:character-map>

 <xsl:template match="/*/text">
  <xsl:analyze-string select=
   "replace(., '\ss\s', ' s&#xA0;')"
   regex="&#xA;">
    <xsl:non-matching-substring>
     <p><xsl:sequence select="."/></p>
    </xsl:non-matching-substring>
  </xsl:analyze-string>
 </xsl:template>

 <xsl:template match="title">
  <h1><xsl:value-of select="."/></h1>
 </xsl:template>
</xsl:stylesheet>

,当应用于同一个XML文档(上图)时,会生成所需的正确结果:

  <h1>Article 1</h1>
<p>Lorem ipsum dolor sit amet, s&nbsp;consectetur adipiscing elit. Donec lorem diam, eleifend sed mollis id, condimentum in velit.</p>
<p>Sed sit amet erat ac mauris adipiscing elementum. Pellentesque eget quam augue, id faucibus magna.</p>
<p>Ut malesuada arcu eu elit sodales sodales. Morbi tristique porttitor tristique. Praesent eget vulputate dui. Cras ut tortor massa, at faucibus ligula.</p>

答案 1 :(得分:3)

以下是我对Dimitre解决方案的调整:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" indent="yes" encoding="UTF-8"/>

 <xsl:template match="/*/text">
   <xsl:for-each select="tokenize( replace(., '\s([kKsSvVzZ])\s', ' $1&#xA0;'), '\n')">
     <p><xsl:value-of select="."/></p>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="title">
  <h1><xsl:value-of select="."/></h1>
 </xsl:template>
</xsl:stylesheet>

备注

  1. 我不确定你的意思是“字母s / S / v / V / k / K / z / Z”。这不是正确的正则表达式。你需要澄清一下。我猜你是指你的角色类[sSvVkKzZ]
  2. 虽然不清楚,但对捷克语的引用表明UTF-8可能是输出编码而不是ASCII的更好选择。
  3. 虽然不清楚,预期的输出标签,建议更合适的序列化将是html。
  4. 作为选择html序列化的一个附带好处,我们不再需要字符映射,使我们的解决方案更简单。我们可以利用内置的字符映射来进行html序列化。
  5. 使用fn:tokenise()消除了对xsl:analyze-string / xsl:non-matching-substring节点的需求,可以说会导致更严格的解决方案。
  6. 用Saxon测试该溶液。
  7. 可能有变化。例如,您可以将replace()调用移动到xsl:value-of中,您可能认为它更易读。
  8. 我的解决方案的缺点是它不能与disable-output-escaping =“yes”一起使用。但是我建议如果你认为你需要这个,请再次强调为什么。任何HTML都需要HTML安全编码,除非它在CDATA部分内。在启用disable-output-escaping的情况下生成HTML的想法是不对的。也许我还没有完全理解这个问题。你能给出一个澄清问题的用例吗?

答案 2 :(得分:2)

你还没有说清楚,但我对这个问题的解释是你想使用第二个xsl:analyze-string来处理第一个的输出。您可以通过将第一个的结果放在变量中来实现,但我的建议是将每个xsl:analyze-string调用放在函数体中,并使用函数组合来组合它们。

<xsl:function name="f:one" as="xs:string">
  <xsl:param name="in" as="xs:string">
  <xsl:analyze-string select="in".../>
</xsl:function>

<xsl:function name="f:two" as="xs:string">
  <xsl:param name="in" as="xs:string">
  <xsl:analyze-string select="in".../>
</xsl:function>

... select="f:two(f:one(.))"...

但是,在你的情况下它更简单,因为第一个xsl:analyze-string可以使用对replace()的简单调用来完成。