获取只有一个祖先节点的值

时间:2013-10-07 19:10:47

标签: xml xslt

我的XML看起来像这样。它是外部供应的,无法更改:

<locations>
  <country iso_code="CA">
    <name>Canada</name>
    <state abbreviation="AB">
      <name>Alberta</name>
      <city>
        <name>Leduc</name>
        <location id="1"/>
      </city>
    </state>
    <state abbreviation="BC">
      <name>British Columbia</name>
      <city>
        <name>Abbotsford</name>
        <location id="2"/>
        <location id="3"/>
      </city>
    </state>
    </country>
  <country iso_code="US">
    <name>United States</name>
    <state abbreviation="AZ">
      <name>Arizona</name>
      <city>
        <name >Wikiup</name>
        <location id="1"/>
      </city>
    </state>
  </country>
</locations>

我的XSL看起来像这样:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*" />
  <xsl:template match="/">
    <xsl:for-each select="//location[@id]">
      <xsl:call-template name="location"/>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="location">
    <xsl:value-of select="@id"/>,
    <xsl:value-of select="ancestor::city[1]"/>,
    <xsl:value-of select="ancestor::state[1]"/>,
    <xsl:value-of select="ancestor::state[1]/@abbreviation"/>,
    <xsl:value-of select="ancestor::country[1]"/>,
    <xsl:value-of select="ancestor::country[1]/@iso_code"/>,
  </xsl:template>

</xsl:stylesheet>

当我运行xsltproc时,我得到了这个输出(我拿出额外的行来使它变得更糟糕):

1,Leduc,AlbertaLeduc,AB,CanadaAlbertaLeducBritish ColumbiaAbbotsford,CA,
2,Abbotsford,British ColumbiaAbbotsford,BC,CanadaAlbertaLeducBritish ColumbiaAbbotsford,CA,
3,Abbotsford,British ColumbiaAbbotsford,BC,CanadaAlbertaLeducBritish ColumbiaAbbotsford,CA,
...etc...

问题是当我做祖先[1]时::它会提取所有祖先的值,而不是我正在寻找的那个。

输出应该是这样的:

1,Leduc,Alberta,AB,Canada,CA,
2,Abbotsford,British Columbia,BC,Canada,CA,
3,Abbotsford,British Columbia,BC,Canada,CA,
...etc...

我尝试使用../../。符号并得到相同的结果。我玩了一些其他符号,它要么不起作用,要么我最终再次使用这些连接的值。

如何只获得我处理的节点的直接父级的值,而不是所有级别的值?

希望我在这里使用正确的术语。这是我第一次使用XSL进行一次性项目。

店里的网络人员也很难过。他们不经常使用XSL。

1 个答案:

答案 0 :(得分:1)

如果您将XML视为框,<value-of>将所选框和它找到的所有框解包,将它们抛弃并留给框中的实际内容。这些是文本节点。属性也被抛弃了,它们是粘在盒子上的一种标签。

如果是<value-of select="ancestor::state">,则会解压缩<state>框,并在其中找到两个框,一个<name>框和一个<city>框。因为你正在使用<strip-space elements="*">它也会抛弃所有的白色空间“泡沫包装”,否则它会保留。它会继续取消装箱并在<name>框中找到“Alberta”,在<city>框中找到另外两个框:<name><location>框。

所以游戏继续:在刚刚取消装箱的<name>框内,找到Leduc并将其保持在Alberta旁边,但它在<location>中找不到任何内容}框。现在,没有什么可以拆包了。所以我们留下了一堆纸板和泡沫包装废物,以及实际内容,AlbertaLeduc(粘合在一起AlbertaLeduc)。

以下是对代码的建议改进:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="iso-8859-1"/>
  <xsl:strip-space elements="*" />

  <xsl:template match="/">
    <xsl:apply-templates select="//location[@id]"/>
  </xsl:template>

  <xsl:template match="location">
    <xsl:value-of select="@id"/>,
    <xsl:value-of select="ancestor::city[1]/name"/>,
    <xsl:value-of select="ancestor::state[1]/name"/>,
    <xsl:value-of select="ancestor::state[1]/@abbreviation"/>,
    <xsl:value-of select="ancestor::country[1]/name"/>,
    <xsl:value-of select="ancestor::country[1]/@iso_code"/>,
  </xsl:template>

</xsl:stylesheet>