XSLT通过XSL-FO用PDF中的新行替换<p> </p>

时间:2017-05-31 11:19:29

标签: xml xslt xsl-fo apache-fop

是否可以用新行替换XSL中的<p></p>字符串?我有一些带有这个标签的文本,我想用一个新行替换它们。如果我想在线之间添加一些间距怎么办?

转换最终生成PDF。

现在我尝试了这个,但没有结果:

<xsl:value-of select="replace($db/content/text, '&lt;p&gt;&lt;/p&gt;', '&#10;')" />

4 个答案:

答案 0 :(得分:2)

Assuming you want to transform the p elements into &#10; characters and you want them to be rendered as line breaks in the PDF output generated from XSL-FO one way is to put the contents into an fo:block element with the attribute linefeed-treatment="preserve" I think, so with e.g.

<xsl:template match="text">
    <fo:block linefeed-treatment="preserve">
        <xsl:apply-templates/>
    </fo:block>
</xsl:template>

<xsl:template match="p">
    <xsl:text>&#10;</xsl:text>
</xsl:template>

and <xsl:apply-templates select="$db/content/text"/> where you currently have the xsl:value-of you should get the output

Aliquam at euismod purus, et tincidunt turpis.
Sed vitae neque tempus, vulputate mi a, scelerisque metus.
Praesent quis hendrerit quam.

for the sample <content><text>Aliquam at euismod purus, et tincidunt turpis.<p></p>Sed vitae neque tempus, vulputate mi a, scelerisque metus.<p></p>Praesent quis hendrerit quam. </text></content> you have shown in the comment.

There might be better and easier ways, in particular if you use XSLT 2.0 where you could use e.g.

<xsl:template match="text">
  <xsl:for-each-group select="node()" group-ending-with="p">
    <fo:block>
      <xsl:apply-templates select="current-group()[not(self::p)]"/>
    </fo:block>
  </xsl:for-each-group>
</xsl:template>

答案 1 :(得分:1)

您写过关于替换<p>代码的文章,因此我认为您的来源是HTML。

如果输出文本也是HTML,那么(我想)你真的想要 对于每个<p>代码:

  • 打印其文字内容,
  • 在其后加<br/>

对于例如内容是非常合理的解决方案。 <td><div>代码。

您可以使用以下XSLT脚本获得此效果:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:template match="p">
    <xsl:value-of select="."/><br/>
  </xsl:template>

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

对于以下输入样本:

<div>
  <p>Abcd</p>
  <p>Efgh Abcd</p>
  <p>Xyz Efgh Abcd</p>
</div>

它给出了以下结果:

<div>
  Abcd<br/>
  Efgh Abcd<br/>
  Xyz Efgh Abcd<br/>
</div>

如果您的目标是转换仅部分 <p>标签(并非全部), 您必须相应地调整模板中的match属性。

答案 2 :(得分:1)

您可以使用空fo:block来表示段落:

<xsl:template match="text">
    <fo:block>
        <xsl:apply-templates/>
    </fo:block>
</xsl:template>

<xsl:template match="p">
    <fo:block space-after="0.5em" />
</xsl:template>

或者,如果text确实只包含文字和<p></p>,那么您可以将每个文字节点分别设为fo:block并删除p

<xsl:template match="text">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="text/text()">
  <fo:block space-after="0.5em">
    <xsl:value-of select="."/>
  </fo:block>
</xsl:template>

<xsl:template match="p" />

如果text包含文字以及p以外的其他元素,那么您又需要我的第一个解决方案或@ martin-honnen的解决方案。

答案 3 :(得分:0)

  

是否可以用新行替换XSL中的<p></p>字符串?

是的,但是,根据您在评论中提出的澄清,这不是您真正想要做的事情。

XSL在输入文档模型(或多或少是DOM)上运行,以生成相同类型的输出模型。它确实可以修改元素的文本内容,这就是我通常倾向于在你的问题中解释“字符串”这个词,但它在那里有点笨拙,特别是在XSLT 1.0版本。这与转换元素完全不同,但是,这似乎是你真正想做的事情。

  

我有一些带有此标签的文字,我想用新的一行替换它们。

不,你没有,至少不是从XML(或HTML)角度来看。您有一个具有混合内容的元素 - 包括字符数据和子元素 - 并且您想要替换某些子元素。在XSL中,您通常会通过与要转换的元素匹配的模板来执行此操作。例如,

<!-- matches `p` elements with no child nodes of any kind (and in particular
     with no text node children).  -->
<xsl:template match="p[not(node())]">
  <!-- the template body presents the replacement for the matched element:
       a text node containing a single newline -->
  <xsl:text>&#xa;</xsl:text>
</xsl:template>

如果您希望转换将其他所有内容转换为自身,那么您还希望在样式表中包含一个标识转换。 Google可以为您提供许多有关XSLT外观的示例。

  

如果我想在线之间添加一些间距怎么办?

这取决于这意味着什么,这取决于输出文档的重要性。您可以轻松地将<p/>元素转换为多个换行符,或<br/>元素,或任意内容。