3

在我的 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>

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

4

3 回答 3

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。要使用的功能是字符映射

那么整个变换就变成了

<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>
于 2012-05-20T22:42:26.247 回答
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 部分中。在启用禁用输出转义的情况下生成 HTML 的想法有些不对劲。也许我还没有完全理解这个问题。你能给出一个用例来澄清这一点吗?
于 2012-05-21T06:45:13.603 回答
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() 的简单调用来完成。

于 2012-05-21T08:07:25.893 回答