gpt4 book ai didi

xslt - 将 OOXML 内联格式转换为合并元素

转载 作者:行者123 更新时间:2023-12-02 11:41:50 25 4
gpt4 key购买 nike

在 OOXML 中,诸如粗体、斜体等格式可以(并且常常令人烦恼地)在多个元素之间分割,如下所示:

<w:p>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t xml:space="preserve">This is a </w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t xml:space="preserve">bold </w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
<w:i/>
</w:rPr>
<w:t>with a bit of italic</w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t xml:space="preserve"> </w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t>paragr</w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t>a</w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t>ph</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> with some non-bold in it too.</w:t>
</w:r>
</w:p>

我需要组合这些格式元素来生成此内容:

<p><b>This is a mostly bold <i>with a bit of italic</i> paragraph</b> with some non-bold in it too.</p>

我最初的方法是在第一次遇到开始格式化标记时使用以下方法写出它:

 <xsl:text disable-output-escaping="yes">&lt;b&gt;</xsl:text>

然后在我处理完每个<w:r>之后,检查下一项以查看格式是否仍然存在。如果不是,请按照添加开始标记的方式添加结束标记。我一直在想一定有更好的方法来做到这一点,如果有任何建议,我将不胜感激。

还应该提到我与 XSLT 1.0 相关。

需要这个的原因是,我们需要在将 XML 文件转换为 OOXML 之前和从 OOXML 转换之后进行比较。额外的格式标记使其看起来好像已进行更改,但实际上并未进行更改。

最佳答案

这是一个完整的 XSLT 1.0 解决方案:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" xmlns:w="w"
exclude-result-prefixes="ext w">
<xsl:output omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="w:p">
<xsl:variable name="vrtfPass1">
<p>
<xsl:apply-templates/>
</p>
</xsl:variable>

<xsl:apply-templates mode="pass2"
select="ext:node-set($vrtfPass1)/*"/>
</xsl:template>

<xsl:template match="w:r">
<xsl:variable name="vrtfProps">
<xsl:for-each select="w:rPr/*">
<xsl:sort select="local-name()"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>

<xsl:call-template name="toHtml">
<xsl:with-param name="pProps" select=
"ext:node-set($vrtfProps)/*"/>
<xsl:with-param name="pText" select="w:t/text()"/>
</xsl:call-template>
</xsl:template>

<xsl:template name="toHtml">
<xsl:param name="pProps"/>
<xsl:param name="pText"/>

<xsl:choose>
<xsl:when test="not($pProps)">
<xsl:copy-of select="$pText"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{local-name($pProps[1])}">
<xsl:call-template name="toHtml">
<xsl:with-param name="pProps" select=
"$pProps[position()>1]"/>
<xsl:with-param name="pText" select="$pText"/>
</xsl:call-template>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template match="/*" mode="pass2">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:call-template name="processInner">
<xsl:with-param name="pNodes" select="node()"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>

<xsl:template name="processInner">
<xsl:param name="pNodes"/>

<xsl:variable name="pNode1" select="$pNodes[1]"/>

<xsl:if test="$pNode1">
<xsl:choose>
<xsl:when test="not($pNode1/self::*)">
<xsl:copy-of select="$pNode1"/>
<xsl:call-template name="processInner">
<xsl:with-param name="pNodes" select=
"$pNodes[position()>1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vbatchLength">
<xsl:call-template name="getBatchLength">
<xsl:with-param name="pNodes"
select="$pNodes[position()>1]"/>
<xsl:with-param name="pName"
select="name($pNode1)"/>
<xsl:with-param name="pCount" select="1"/>
</xsl:call-template>
</xsl:variable>

<xsl:element name="{name($pNode1)}">
<xsl:copy-of select="@*"/>

<xsl:call-template name="processInner">
<xsl:with-param name="pNodes" select=
"$pNodes[not(position()>$vbatchLength)]
/node()"/>
</xsl:call-template>
</xsl:element>

<xsl:call-template name="processInner">
<xsl:with-param name="pNodes" select=
"$pNodes[position()>$vbatchLength]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>

<xsl:template name="getBatchLength">
<xsl:param name="pNodes"/>
<xsl:param name="pName"/>
<xsl:param name="pCount"/>

<xsl:choose>
<xsl:when test=
"not($pNodes) or not($pNodes[1]/self::*)
or not(name($pNodes[1])=$pName)">
<xsl:value-of select="$pCount"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="getBatchLength">
<xsl:with-param name="pNodes" select=
"$pNodes[position()>1]"/>
<xsl:with-param name="pName" select="$pName"/>
<xsl:with-param name="pCount" select="$pCount+1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

当此转换应用于以下 XML 文档时(基于提供的内容,但变得更加复杂以显示如何覆盖更多边缘情况):

<w:p xmlns:w="w">
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t xml:space="preserve">This is a </w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t xml:space="preserve">bold </w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
<w:i/>
</w:rPr>
<w:t>with a bit of italic</w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
<w:i/>
</w:rPr>
<w:t> and some more italic</w:t>
</w:r>
<w:r>
<w:rPr>
<w:i/>
</w:rPr>
<w:t> and just italic, no-bold</w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t xml:space="preserve"></w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t>paragr</w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t>a</w:t>
</w:r>
<w:r>
<w:rPr>
<w:b/>
</w:rPr>
<w:t>ph</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> with some non-bold in it too.</w:t>
</w:r>
</w:p>

产生了想要的正确结果:

<p><b>This is a bold <i>with a bit of italic and some more italic</i></b><i> and just italic, no-bold</i><b>paragraph</b> with some non-bold in it too.</p>

说明:

  1. 这是一个两遍转换。第一遍相对简单,将源 XML 文档(在我们的具体情况下)转换为以下内容:

pass1 结果(缩进以方便阅读):

<p>
<b>This is a </b>
<b>bold </b>
<b>
<i>with a bit of italic</i>
</b>
<b>
<i> and some more italic</i>
</b>
<i> and just italic, no-bold</i>
<b/>
<b>paragr</b>
<b>a</b>
<b>ph</b> with some non-bold in it too.</p>

.2。 第二遍(以“pass2”模式执行)将任意一批连续且同名的元素合并为具有该名称的单个元素。它递归地调用合并元素的子元素——从而合并任意深度的批处理。

.3。 请注意:我们不(也不能)使用轴 following-sibling::preceding-sibling,因为只有节点(被合并)在顶层实际上是 sibling 。由于这个原因,我们将所有节点作为一个节点集进行处理。

.4。 这个解决方案是完全通用的 - 它合并任意深度的任何一批连续的同名元素 - 并且没有硬编码特定名称。

关于xslt - 将 OOXML 内联格式转换为合并元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6297606/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com