【问题标题】:xsl 1.0 copy-of loses formatting in xsl-fo outputxsl 1.0 副本在 xsl-fo 输出中丢失格式
【发布时间】:2013-09-20 16:03:16
【问题描述】:

我的xml如下:

<valid_path>
    <document var_name="some_value">
        <processControls>
            <p>Lots of good text here ...</p>
            <ul class="unIndentedList">
                <li> Graphical display of system</li>
                <li> Other bulleted items ...</li>
            </ul>
            <p>etc. etc. etc.</p>
        </processControls>
    </document>
</valid_path>

我的输入是由这个决定的:

<xsl:variable name="processControlsValue" select="/valid_path/document[@var_name='some_value']/processControls" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"/>

我正在调用递归模板来替换在某些输入中找到的给定字符串。调用如下。

<xsl:call-template name="bulRep">
    <xsl:with-param name="text" select="$processControlsValue"/>
    <xsl:with-param name="replace" select="'Graphical'"/>
    <xsl:with-param name="by" select="'foofoobars'"/>
</xsl:call-template>

这是模板。

<xsl:template name="bulRep">
    <xsl:param name="text"/>
    <xsl:param name="replace"/>
    <xsl:param name="by"/>
    <xsl:choose>
        <xsl:when test="contains($text, $replace)">
            <xsl:value-of select="substring-before($text,$replace)"/>
            <xsl:value-of select="$by"/>
            <xsl:call-template name="bulRep">
                <xsl:with-param name="text" select="substring-after($text,$replace)"/>
                <xsl:with-param name="replace" select="$replace"/>
                <xsl:with-param name="by" select="$by"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text"/>
            <!--<xsl:apply-templates select="$text" />-->
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

模板的工作原理是替换找到的文本。 (例如,“Graphical”确实被“foofoobars”取代)我遇到的问题是丢失了 value-of 或 copy-of 的格式。我意识到 value-of 将返回文本,而不是文本和格式,并且我发现许多帖子指示其他人使用 copy-of 来保留格式。但是,这不起作用。输出只是一个连续的文本行。

现在,如果我使用 apply-templates 行(当前已注释掉)而不是 value-of 行,并确保我点击了模板的“否则”部分,我会得到所需的输出。我会得到段落、项目符号列表等。但是使用 value-of 或 copy-of 只会获取文本,如果存在字符串匹配,使用 apply-templates 会中断。

我的最终结果是使用 xsl-fo 的 PDF。

我现在看到的:

这里有很多很好的文字...系统的foofoobars显示其他项目符号项...等等等等等等

我想看的:

这里有很多好文...

• 系统的foofoobars 显示

• 其他项目符号...

等等。等等等等。

【问题讨论】:

  • 你能说明你是如何设置变量$processControlsValue的吗?查找和替换模板假定它只是传递文本,但如果你传递一个包含节点列表的变量,那么它将无法按预期工作。您能否编辑您的问题以显示您的输入样本和您期望的输出,然后我们可以帮助调整您的方法。我认为它不需要任何重大改变。谢谢!
  • @TimC - 感谢您的跟进。我已经添加了我的输入。使用应用模板在输出中正确显示输入。我就停在那里。但是,有一些布局问题我需要纠正,所以我需要使用递归替换模板。
  • 我们需要查看您输入的 XML 结构。
  • 我已经用 xml 更新了我的帖子。

标签: xml xslt xsl-fo


【解决方案1】:

问题在于,如果您使用的查找和替换模板仅用于处理作为参数传入的文本。如果您要传入节点列表,那么当您执行“包含”之类的字符串函数时,它将只使用第一个节点的文本。或者,如果您传入具有多个后代的单个元素,则字符串值将被视为所有后代文本节点的串联。

我认为您可能需要做的是利用此处的身份转换,这可能是您在提到 xsl:apply-templates 时已经在做的事情,但有一个单独的模板匹配文本节点,然后您可以在其中调用查找和替换模板

<xsl:template ....>
  <xsl:variable name="processControlsValue" 
                select="/valid_path/document[@var_name='some_value']/processControls" />
  <xsl:apply-templates select="$processControlsValue" mode="replace">
    <xsl:with-param name="replace" select="'Graphical'"/>
    <xsl:with-param name="by" select="'foofoobars'"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="@*|node()[not(self::text())]" mode="replace">
  <xsl:param name="replace"/>
  <xsl:param name="by"/>
  <xsl:copy>
    <xsl:apply-templates select="@*|node()" mode="replace">
      <xsl:with-param name="replace" select="$replace"/>
      <xsl:with-param name="by" select="$by"/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

<xsl:template match="text()" mode="replace">
  <xsl:param name="replace"/>
  <xsl:param name="by"/>
  <xsl:call-template name="bulRep">
    <xsl:with-param name="text" select="."/>
    <xsl:with-param name="replace" select="$replace"/>
    <xsl:with-param name="by" select="$by"/>
  </xsl:call-template>
</xsl:template>

注意,我使用了mode="replace" 来防止与您可能​​拥有的模板发生潜在冲突。如果没有这样的冲突,可能会删除该模式。

所以,这个想法在这两个模板中,它复制任何现有的元素和属性,但是当它找到一个文本节点时,它只对文本进行查找和替换。

顺便说一句,如果您使用的是 XSLT 2.0,则可以只使用 replace 函数而不是命名模板

<xsl:template match="text()" mode="replace">
   <xsl:param name="replace"/>
   <xsl:param name="by"/>
   <xsl:value-of select="replace(., $replace, $by)" />
</xsl:template>

编辑:作为一个完整的工作示例,试试这个 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/">
      <xsl:variable name="processControlsValue" select="/valid_path/document[@var_name='some_value']/processControls"/>
      <xsl:apply-templates select="$processControlsValue" mode="replace">
         <xsl:with-param name="replace" select="'Graphical'"/>
         <xsl:with-param name="by" select="'foofoobars'"/>
      </xsl:apply-templates>
   </xsl:template>

   <xsl:template match="@*|node()[not(self::text())]" mode="replace">
      <xsl:param name="replace"/>
      <xsl:param name="by"/>
      <xsl:copy>
         <xsl:apply-templates select="@*|node()" mode="replace">
            <xsl:with-param name="replace" select="$replace"/>
            <xsl:with-param name="by" select="$by"/>
         </xsl:apply-templates>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="text()" mode="replace">
      <xsl:param name="replace"/>
      <xsl:param name="by"/>
      <xsl:call-template name="bulRep">
         <xsl:with-param name="text" select="."/>
         <xsl:with-param name="replace" select="$replace"/>
         <xsl:with-param name="by" select="$by"/>
      </xsl:call-template>
   </xsl:template>

   <xsl:template name="bulRep">
      <xsl:param name="text"/>
      <xsl:param name="replace"/>
      <xsl:param name="by"/>
      <xsl:choose>
         <xsl:when test="contains($text, $replace)">
            <xsl:value-of select="substring-before($text,$replace)"/>
            <xsl:value-of select="$by"/>
            <xsl:call-template name="bulRep">
               <xsl:with-param name="text" select="substring-after($text,$replace)"/>
               <xsl:with-param name="replace" select="$replace"/>
               <xsl:with-param name="by" select="$by"/>
            </xsl:call-template>
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$text"/><!--<xsl:apply-templates select="$text" />-->
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例 XML 时,将输出以下内容。可以看出,文本中的“Graphical”一词已被“foofoobars”取代。

<processControls>
<p>Lots of good text here ...</p>
<ul class="unIndentedList">
<li> foofoobars display of system</li>
<li> Other bulleted items ...</li>
</ul>
<p>etc. etc. etc.</p>
</processControls>

【讨论】:

  • 我现在实际上没有得到任何输出。也许我误解了我建议的下一步可能是什么。处理正确地落在模板 match="@*|node()[not(self::text())]" 模板中。但是我在输出中看不到任何文本(格式化或纯文本)。
  • 我添加了一些 XSLT 的完整工作副本来演示它。您可能正在 XSLT 中做其他发生冲突的事情,但希望它应该证明主体。
  • 也许是因为我分块发布/编辑造成了一些混乱。问题不是让文本替换工作,而是保持格式。我已经更新了 OP 在运行替换模板后的外观以及我期望它的外观。单独运行工作副本(谢谢)也会丢失段落和项目符号列表。
  • 我在xsltcake.com/slices/eBz6Um 运行了我的最终XSLT 示例,它似乎保持了预期的“p”和“li”元素。让我感到困惑的是,问题是关于输出 xsl-fo,但 XML 示例实际上包含 HTML。替换文本后是否正在运行其他进程?也许问题出在那儿?
  • 只是使用独立的,我将 xsl 附加到 xml 并且我正在浏览器 (Firefox 23) 中查看 xml。输出对我来说只是一行文本。
猜你喜欢
  • 2017-08-13
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多