我是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模式匹配所有'bar'元素而不仅仅是正确的元素,但我不确定原因。
我做错了什么,有更好的方法吗?
答案 0 :(得分: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}"/>
这就是您观察到的结果的产生方式。
解决方案:使用XSLT current()
功能:
<bar label="{@label}" index="{@index}"
type="{$master/foo/bar[@label=current()/@label][4]/@type}"/>
完整转换(我已将网址更改为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>
<强> II。使用keys :
可能提高解决方案的效率<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>