1

我正在从一个 xml 文件创建一个 WordML 文档,该文件的元素有时包含 html 格式的文本。

<w:p>
  <w:r>
    <w:t> html formatted content is in here taken from xml file! </w:t>
  </w:r>
</w:p>

这就是我的模板的设置方式。我有一个递归调用模板函数,它对源 xml 内容进行文本替换。当遇到“ <b>”标签时,我在 CDATA 中输出一个包含“ </w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t>”的字符串,以关闭当前运行并启动一个启用粗体格式的新运行。当它到达一个“ </b>”标签时,它用下面的 CDATA 字符串“ </w:t></w:r><w:r><w:t>”替换它。

我想做的是使用 XSL 关闭运行标记并开始新的运行,而不使用 CDATA 字符串插入。这可能吗?

4

4 回答 4

3

Working with WordML is tricky. One tip when converting arbitrary XML to WordML using XSLT is to not worry about the text runs when processing blocks, but to instead create a template that matches text() nodes directly, and create the text runs there. It turns out that Word doesn't care if you nest text runs, which makes the problem much easier to solve.

   <xsl:template match="text()" priority="1">
         <w:r>
            <w:t>
               <xsl:value-of select="."/>
            </w:t>
         </w:r> 
   </xsl:template>

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

   <xsl:template match="para">
      <w:p>
         <xsl:apply-templates select="text() | *" />
      </w:p>
   </xsl:template>

   <xsl:template match="b">
      <w:r>
         <w:rPr>
            <w:b />
         </w:rPr>
         <w:t><xsl:apply-templates /></w:t>
      </w:r>
   </xsl:template>

This avoids the bad XSLT technique of inserting tags directly as escaped text. You'll end up with the bold tag as a nested text run, but as I said, Word couldn't care less. If you use this technique, you'll need to be careful to not apply templates to the empty space between paragraphs, since it will trigger the text template and create an out-of-context run.

于 2008-10-30T17:38:23.447 回答
0

根据您的描述,听起来您可以解析嵌入的 html。如果是这样,只需应用模板就可以满足您的需求。输出中的 wordML 可能不正确,但希望这会有所帮助。

样本输入:

<text>
  <para>
    Test for paragraph 1
  </para>
  <para>
    Test for <b>paragraph 2</b>
  </para>
</text>

转换:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:w="http://foo">
<xsl:template match="/">
  <w:p>
    <w:r>
      <xsl:apply-templates/>
    </w:r>     
  </w:p>
</xsl:template>
  <xsl:template match="para">
    <w:t>
      <xsl:apply-templates/>
    </w:t>
  </xsl:template>

  <xsl:template match="b">
    <w:rPr>
      <w:b/>
    </w:rPr>
      <xsl:value-of select="."/>
  </xsl:template>
</xsl:stylesheet> 

结果:

<w:p xmlns:w="http://foo">
  <w:r>
    <w:t>
      Test for paragraph 1
    </w:t>
    <w:t>
      Test for <w:rPr><w:b /></w:rPr>paragraph 2
    </w:t>
  </w:r>
</w:p>
于 2008-10-27T14:30:44.827 回答
0

如果只有我理解您的问题,我很可能会为您提供帮助... html 是在 CDATA 部分中还是被解析为输入文档的一部分(因此是格式正确的 XML)?由于您谈论“文本替换”,我假设您将“html 格式化内容”视为单个字符串 (CDATA),因此需要一个递归调用模板函数来执行字符串替换。您将能够使用 XSL 匹配模板来完成您现在正在做的事情的唯一方法是使 html 成为已解析文档(您的输入文档)的一部分。在这种情况下,您可以只匹配b标记并将其替换为适当的输出(再次:假设它始终可以被解析为有效的 XML)。你的问题现在已经转移了......因为(如果我正确理解你的问题)你是什么w:tw:r元素,然后“重新打开”它们……这很难,因为(正如您可能怀疑的那样)很难在 XSLT 中很好地做到这一点(您不能只在模板 A 中创建一个元素,然后在模板 B 中将其关闭)。你必须开始弄乱未转义的输出等才能做到这一点。我现在做了很多假设,但这里有一个小例子可以帮助你:

输入.xml

<doc xmlns:w="urn:schemas-microsoft-com:office:word">
<w:p>
  <w:r>
    <w:t>before<b>bold</b>after</w:t>
  </w:r>
</w:p>
</doc>

convert_html.xsl

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

<xsl:template match="/doc/w:p/w:r/w:t//b">
  <xsl:value-of select="'&lt;/w:t>&lt;/w:r>&lt;w:r>&lt;w:rPr>&lt;w:b/>&lt;/w:rPr>&lt;w:t>'" disable-output-escaping="yes" />
  <xsl:apply-templates select="@*|node()"/>
  <xsl:value-of select="'&lt;/w:t>&lt;/w:r>&lt;w:r>&lt;w:t>'" disable-output-escaping="yes" />
</xsl:template>

现在运行

xalan input.xml convert_html.xsl

生产

<?xml version="1.0" encoding="UTF-8"?><doc xmlns:w="urn:schemas-microsoft-com:office:word">
<w:p>
  <w:r>
    <w:t>before</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t>bold</w:t></w:r><w:r><w:t>after</w:t>
  </w:r>
</w:p>
</doc>

我想这就是你想要的。

希望这对您有所帮助。

于 2008-10-27T06:57:32.680 回答
0

为了完全完成 HTML > WordML,我推荐您的代码的这个编辑版本:

<xsl:template match="Body"><xsl:apply-templates select="p"/></xsl:template>

<xsl:template match="text()" priority="1"><w:r><w:t><xsl:value-of select="."/></w:t></w:r></xsl:template>

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

<xsl:template match="p"><w:p><xsl:apply-templates select="text() | *" /></w:p></xsl:template>

<xsl:template match="b"><w:r><w:rPr><w:b /></w:rPr><xsl:apply-templates /></w:r></xsl:template>
<xsl:template match="i"><w:r><w:rPr><w:i /></w:rPr><xsl:apply-templates /></w:r></xsl:template>
<xsl:template match="u"><w:r><w:rPr><w:u w:val="single" /></w:rPr><xsl:apply-templates /></w:r></xsl:template>

假设您的 HTML 包含在标记中的 XML 中某处

于 2009-07-27T16:54:04.357 回答