XSLT从docx document.xml读取目录

时间:2015-01-27 11:43:56

标签: xslt docx tableofcontents

我正在尝试使用XSLT从docx的document.xml文件中检索TOC

这是我的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:sdtContent范围之外还有额外的w:p标记值。

我是XSLT的初学者,不知道我在这里做错了什么。

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

1 个答案:

答案 0 :(得分:2)

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