如何在XSLT中选择特定的节点集

4

我目前使用的xslt在根上生成所有标签。 我需要获取<row>集和<config>集。

源XML:

<root>
    <postdate>2011-03-30</postdate>
    <location>84</location>
    <meal>07:36</meal>
    <config>
        <postdate>2011-03-30</postdate>
        <location>84</location>
        <meal>07:36</meal>
        <checknumber>91339082011-03-30T07:36:12</checknumber>
    </config>
    <items>
        <row>
            <descriptor>7297364</descriptor>
            <qty>1</qty>
            <price>33</price>
            <value>33</value>
            <recordtype>1</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
        <row>
            <descriptor>7794473</descriptor>
            <qty>1</qty>
            <price>60</price>
            <value>60</value>
            <recordtype>1</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
    </items>
    <tenders>
        <row>
            <id>13</id>
            <value>117.99</value>
            <recordtype>2</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
    </tenders>
    <taxes>
        <row>
            <id>2</id>
            <value>8.25</value>
            <recordtype>3</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
    </taxes>
</root>

尝试的 XSLT:

<xsl:stylesheet version="1.0" exclude-result-prefixes="msxsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:template match="row/*">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

期望输出:

<root>
    <config>
        <postdate>2011-03-30</postdate>
        <location>84</location>
        <meal>07:36</meal>
        <checknumber>91339082011-03-30T07:36:12</checknumber>
    </config>
    <row>
        <descriptor>7297364</descriptor>
        <qty>1</qty>
        <price>33</price>
        <value>33</value>
        <recordtype>1</recordtype>
        <postdate>2011-03-30</postdate>
        <location>84</location>
    </row>
    <row>
        <descriptor>7794473</descriptor>
        <qty>1</qty>
        <price>60</price>
        <value>60</value>
        <recordtype>1</recordtype>
        <postdate>2011-03-30</postdate>
        <location>84</location>
    </row>
    <row>
        <id>13</id>
        <value>117.99</value>
        <recordtype>2</recordtype>
        <postdate>2011-03-30</postdate>
        <location>84</location>
    </row>
    <row>
        <id>2</id>
        <value>8.25</value>
        <recordtype>3</recordtype>
        <postdate>2011-03-30</postdate>
        <location>84</location>
    </row>
</root>

首先使用XPath匹配config元素,然后在其中执行另一个XPath匹配config,即第一次匹配="/root/config",第二次应该只是匹配="/items/config"。XSLT不是我的强项(我经常使用C#和XPath查询,它们似乎“大致”正确,尽管您使用了通配符(?)即row/*,我假设这意味着返回行中的所有内容?此外,您可能需要指定根并逐步到达节点,或者您可以在XPath中使用//表示文档中的任何位置。 - Paul Sullivan
XPath是XSLT用于遍历树的工具,所以请阅读一些相关资料(它非常简单)。 - Paul Sullivan
2个回答

8

这是一个简短而简单的转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "node()[not(self::root or ancestor-or-self::config or ancestor-or-self::row)]">
  <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:
<root>
    <postdate>2011-03-30</postdate>
    <location>84</location>
    <meal>07:36</meal>
    <config>
        <postdate>2011-03-30</postdate>
        <location>84</location>
        <meal>07:36</meal>
        <checknumber>91339082011-03-30T07:36:12</checknumber>
    </config>
    <items>
        <row>
            <descriptor>7297364</descriptor>
            <qty>1</qty>
            <price>33</price>
            <value>33</value>
            <recordtype>1</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
        <row>
            <descriptor>7794473</descriptor>
            <qty>1</qty>
            <price>60</price>
            <value>60</value>
            <recordtype>1</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
    </items>
    <tenders>
        <row>
            <id>13</id>
            <value>117.99</value>
            <recordtype>2</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
    </tenders>
    <taxes>
        <row>
            <id>2</id>
            <value>8.25</value>
            <recordtype>3</recordtype>
            <postdate>2011-03-30</postdate>
            <location>84</location>
        </row>
    </taxes>
</root>

产生所需的、正确的结果:
<root>
   <config>
      <postdate>2011-03-30</postdate>
      <location>84</location>
      <meal>07:36</meal>
      <checknumber>91339082011-03-30T07:36:12</checknumber>
   </config>
   <row>
      <descriptor>7297364</descriptor>
      <qty>1</qty>
      <price>33</price>
      <value>33</value>
      <recordtype>1</recordtype>
      <postdate>2011-03-30</postdate>
      <location>84</location>
   </row>
   <row>
      <descriptor>7794473</descriptor>
      <qty>1</qty>
      <price>60</price>
      <value>60</value>
      <recordtype>1</recordtype>
      <postdate>2011-03-30</postdate>
      <location>84</location>
   </row>
   <row>
      <id>13</id>
      <value>117.99</value>
      <recordtype>2</recordtype>
      <postdate>2011-03-30</postdate>
      <location>84</location>
   </row>
   <row>
      <id>2</id>
      <value>8.25</value>
      <recordtype>3</recordtype>
      <postdate>2011-03-30</postdate>
      <location>84</location>
   </row>
</root>

说明:

  1. 使用和覆盖身份规则

  2. 正确使用ancestor-or-self::轴。


1
能够解释一下这个是如何工作的吗?目前这个解决方案对于那些试图达到类似但不同的结果的人来说并不是很有帮助。 - Daniil Shevelev
1
@DaniilShevelev,这个答案中的2点解释涉及到基本的XSLT和XPath概念,这些概念对于XSLT程序员来说是众所周知的。这些概念在好书(@MichaelKay)和Pluralsight培训课程中都有很好的解释--包括许多页和小时的视频。在这里复制这些内容是不切实际的,也没有人会允许这样做。我建议阅读这样一本好书和/或观看关于XSLT的Pluralsight培训课程。 - Dimitre Novatchev

0

我搞定了。这个XSLT对我有用。

<xsl:stylesheet version="1.0" exclude-result-prefixes="msxsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:template match="/">
        <root>
            <xsl:for-each select="//row">
                <row>
                    <xsl:apply-templates/>
                </row>
            </xsl:for-each>
            <xsl:for-each select="//config">
                <config>
                    <xsl:apply-templates/>
                </config>
            </xsl:for-each>
        </root>
    </xsl:template>
    <xsl:template match="*">
        <xsl:element name="{name()}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

有一个更简单和更短的解决方案(请参见我的答案)。你需要习惯使用和覆盖身份模板——这是最基本的XSLT设计模式之一。 - Dimitre Novatchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接