XSLT 从 docx document.xml 中读取了 Table 的内容

XSLT read Table of contents from docx document.xml

我正在尝试使用 XSLT

从 docx 的 document.xml 文件中检索目录

这是我的 XSLT:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sap="http://www.sap.com/sapxsl" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" exclude-result-prefixes="w" version="2.0">
  <xsl:output indent="yes" method="xml"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="w:sdt">
        <xsl:element name="root">

          <xsl:attribute name="label">
            <xsl:value-of select="w:sdtPr/w:docPartObj/w:docPartGallery/@w:val"/>
          </xsl:attribute>

          <xsl:for-each select="w:sdtContent/w:p">
            <xsl:if test="w:pPr/w:pStyle/@w:val">

              <xsl:element name="sec">

                <xsl:attribute name="label">
                  <xsl:value-of select="w:pPr/w:pStyle/@w:val"/>
                </xsl:attribute>

                <xsl:attribute name="anchor">
                  <xsl:value-of select="w:hyperlink/@w:anchor"/>
                </xsl:attribute>

                <xsl:attribute name="title">
                  <xsl:value-of select="w:hyperlink/w:r/w:t"/>
                </xsl:attribute>

              </xsl:element>

            </xsl:if>
          </xsl:for-each>
        </xsl:element>
      </xsl:if>
  </xsl:template>
</xsl:transform>

我得到了想要的结果,但是 w:p 标签值超出了 w:sdtContent 范围。

我是 XSLT 的初学者,不确定我做错了什么。

(如果来源 xml 有帮助,请告诉我我会 post 在这里。)

XSLT 使用 a set of default rules 从根节点开始处理其输入。这些默认规则可以被覆盖——但你不能那样做。我怀疑您看到的不需要的额外输出来自默认规则。

您的样式表包含一个模板 <xsl:template match="w:sdt"> 并且 XSLT 处理器 执行 运行 该模板,但仅当它到达 <w:sdt>当它遍历输入文档时。

如果您想自己从根节点开始并指示 XSLT 处理器应该查看哪些节点,请通过编写与根节点匹配的模板来覆盖默认行为 ( <xsl:template match="/">).

<xsl:transform
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:sap="http://www.sap.com/sapxsl"
  xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
  exclude-result-prefixes="w"
>
  <xsl:output indent="yes" method="xml" />
  <xsl:strip-space elements="*" />

  <xsl:template match="/">
    <xsl:apply-temmplates select="//w:sdt" />
  </xsl:template>

  <xsl:template match="w:sdt">
    <root label="{w:sdtPr/w:docPartObj/w:docPartGallery/@w:val}" />
      <xsl:apply-templates select="w:sdtContent/w:p[w:pPr/w:pStyle/@w:val]" />
    </root>
  </xsl:template>

  <xsl:template match="w:sdtContent/w:p">
    <sec 
      label="{w:pPr/w:pStyle/@w:val}"
      anchor="{w:hyperlink/@w:anchor}"
      title="{w:hyperlink/w:r/w:t}"
    />
  </xsl:template>
</xsl:transform>

其他说明:

  • 不要写<xsl:element name="foo">。写入 <foo>.
  • 不写<xsl:attribute name="bar"><foo bar="{xpath-expr}">.
  • 避免<xsl:for-each>。使用 <xsl:apply-templates><xsl:template>.
  • 避免使用 <xsl:if> 过滤您要处理的节点。编写一个适当的 XPath 表达式,只选择您要处理的节点。
  • 可能有帮助的阅读:How <xsl:apply-templates> works