xsl,只复制一个,但有所有内容?

时间:2013-09-05 14:30:10

标签: xml xslt

我有

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
<article lang="en">
     <articleinfo>
            <title>Test Article</title>
     </articleinfo>
     <sect1 label="">
            <title>Test1 Section</title>
            <para>Some content</para>
    </sect1>
    <sect1>
            <title>Test2 Section</title>
            <para>Another content</para>
    </sect1>
</article>

我想只提取一个标题为“Test1”的sect1, 所以我写了这么简单的xsl转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:d="http://docbook.org/ns/docbook">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="article/sect1[contains(title, 'Test1')]">
  <xsl:message>Match</xsl:message>
  <xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

但由于某些未知原因,此类转换不会仅复制带有提及标题的sect1,还会复制所有XML文件减去标记的内容:

xsltproc ./extract_sect1.xsl test.xml 
Match
<?xml version="1.0"?>


            Test Article

    <sect1 label="">
            <title>Test1 Section</title>
            <para>Some content</para>
    </sect1>

            Test2 Section
            Another content

那么问题,为什么我得到“Test2 Section”和“Another content”, 我该如何解决这种情况?

2 个答案:

答案 0 :(得分:2)

请将此模板添加到您的XSLT:

<xsl:template match="text()"/>

,您的输出将如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<sect1 label="">
    <title>Test1 Section</title>
    <para>Some content</para>
</sect1>

我认为这是想要的输出?

祝你好运, 彼得

答案 1 :(得分:1)

XSLT对所有节点都有默认built-in template rules,如果您没有指定显式模板,则适用。处理始终通过将模板应用于文档根节点开始,元素的默认规则仅为

<xsl:apply-templates/>

(即继续递归地将模板应用于子节点)。您的问题是文本节点的默认模板规则是将文本输出到结果树。因此,对于除article/sect1[contains(title, 'Test1')]之外的所有节点,您将获得所有后代文本节点输出到结果。

有两种显而易见的方法,您可以定义

<xsl:template match="text()" />

禁止默认文本节点行为,或者添加

<xsl:template match="/">
  <xsl:apply-templates select="article/sect1[contains(title, 'Test1')]" />
</xsl:template>

直接跳到您感兴趣的部分,将默认模板应用到其他元素。