【问题标题】:XSLT read Table of contents from docx document.xmlXSLT 从 docx document.xml 读取目录
【发布时间】:2015-03-26 00:30:06
【问题描述】:

我正在尝试使用 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:sdtContent 范围之外还有额外的 w:p 标签值。

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

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

【问题讨论】:

  • 您的 XSLT 在语法上无效。请先解决这个问题。

标签: xslt docx tableofcontents


【解决方案1】:

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

您的样式表包含一个模板&lt;xsl:template match="w:sdt"&gt;,XSLT 处理器确实运行该模板,但仅当它在遍历输入文档时到达&lt;w:sdt&gt;

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

<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>

其他说明:

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

【讨论】:

  • Tomalak,非常感谢您的解释和代码。也感谢非常有用的链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多