3

我对 XML 有点陌生,我有一个问题,我有一个生成的 XML 文档,其中某些元素的属性列表不完整。我正在尝试实现一个 XSLT 样式表,该样式表将它与一个主文档(它包含所有属性的默认值)交叉引用,以便用默认值填充任何缺失的属性。

例如,以下不完整的 XML 文档:

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="two" index="2"/>
</foo>

bar 元素缺少属性“type”,我想根据“label”的值从以下主文档中填充默认值:

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="one" index="1" type="type1"/>
  <bar label="two" index="2" type="type2"/>
  <bar label="three" index="3" type="type3"/>
</foo>

期望的结果是:

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="two" index="2" type="type2"/>
</foo>

我的 XSLT 样式表尝试使用 'document()' 和 XPath 的组合来执行此操作,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:variable name="master" select="document('master.xml')"/>

  <!-- Template matching 'root' of XML document -->
  <xsl:template match="/">
    <xsl:apply-templates select="foo"/>
  </xsl:template>

  <!-- Template for generating 'foo' element -->
  <xsl:template match="foo">
    <foo>
      <xsl:apply-templates select="bar"/>
    </foo>
  </xsl:template>

  <!-- Template for generating 'bar' element -->
  <xsl:template match="bar">
    <bar label="{@label}" index="{@index}" type="{$master/foo/bar[@label=@label][1]/@type}"/>
  </xsl:template>

</xsl:stylesheet>

但是,这不起作用,并为我提供了“bar”元素的默认“type”属性,其中“label”为“one”而不是“two”:

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="two" index="2" type="type1"/>
</foo>

一些调查显示 XPath 模式匹配所有的“条形”元素,而不仅仅是正确的元素,但我不知道为什么。

我做错了什么,有更好的方法吗?

4

1 回答 1

2

问题出在这一行

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[@label=@label][1]/@type}"/> 

您实际上是在检查元素的label属性bar是否等于自身——这相当于:

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[true()][2]/@type}"/> 

这相当于

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[1]/@type}"/> 

这就是您观察到的结果的产生方式。

解决方案:使用 XSLTcurrent()功能:

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[@label=current()/@label][4]/@type}"/> 

完整的转换变为(我已将 URL 更改master.xml为能够在本地计算机上运行转换):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:variable name="master" select=
      "document('file:///c:/temp/delete/master.xml')"/>

      <!-- Template matching 'root' of XML document -->
      <xsl:template match="/">
        <xsl:apply-templates select="foo"/>
      </xsl:template>

      <!-- Template for generating 'foo' element -->
      <xsl:template match="foo">
        <foo>
          <xsl:apply-templates select="bar"/>
        </foo>
      </xsl:template>

      <!-- Template for generating 'bar' element -->
      <xsl:template match="bar">
        <bar label="{@label}" index="{@index}"
        type="{$master/foo/bar[@label=current()/@label][5]/@type}"/>
      </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<foo>
    <bar label="two" index="2"/>
</foo>

产生了想要的正确结果:

<foo><bar label="two" index="2" type="type2"/></foo>

二、使用键可能更有效的解决方案

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

 <xsl:key name="kTypeByLabel" match="@type" use="../@label"/>

      <xsl:variable name="master" select=
      "document('file:///c:/temp/delete/master.xml')"/>

      <!-- Template matching 'root' of XML document -->
      <xsl:template match="/">
        <xsl:apply-templates select="foo"/>
      </xsl:template>

      <!-- Template for generating 'foo' element -->
      <xsl:template match="foo">
        <foo>
          <xsl:apply-templates select="bar"/>
        </foo>
      </xsl:template>

      <!-- Template for generating 'bar' element -->
      <xsl:template match="bar">
        <xsl:variable name="vCurrent" select="."/>
        <xsl:variable name="vDefault">
          <xsl:for-each select="$master">
            <xsl:value-of select=
                "key('kTypeByLabel', $vCurrent/@label)"/>
          </xsl:for-each>
        </xsl:variable>

        <bar label="{@label}" index="{@index}" type="{$vDefault}"/>
      </xsl:template>
</xsl:stylesheet>

当此转换应用于(相同)提供的 XML 文档(上图)时,会产生所需的正确结果

<foo>
   <bar label="two" index="2" type="type2"/>
</foo>
于 2012-04-18T01:37:13.530 回答