2012-04-17 53 views
3

交叉引用和扩充XSLT中的XML元素问题我对XML有一个新手,并且遇到了一个问题,那就是我生成了一个XML文档,该文档已经为其生成了一些属性列表元素不完整。我试图实现一个XSLT样式表,它与一个主文档(为所有属性默认值完成)交叉引用它,以便使用默认值填充任何缺失的属性。使用document()

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

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

酒吧元件具有缺少的属性“类型”,我想根据该值与从以下主文档的默认值来填充'标签' 的:

<?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样式表,试图做到这一点使用的组合“文件()”和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[@[email protected]][1]/@type}"/> 
    </xsl:template> 

</xsl:stylesheet> 

然而,这并不工作,给我默认的“类型”属性的用“酒吧”元素的“一个”标签',而不是“二”:

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

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

我在做什么错,是否有更好的方法来做到这一点?

+0

这似乎总是如此[@ label = @ label]。你想要[@ label = current()/ @ label]吗? – Pawel 2012-04-18 00:30:24

回答

2

的问题是在这条线

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

你基本上是检查是否一个bar元素的label属性等于本身 - 这相当于:

<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> 

当这个transf ormation施加在提供的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> 
+0

的确,添加'current()'解决了我的问题。上下文是我努力使用XSLT来解决问题的其中一件事情,特别是在尝试引用来自多个位置的信息时。谢谢你的帮助。非常感谢!也感谢看似有趣的替代解决方案。 – 2012-04-20 09:44:42

+0

@monkey_nuts:不客气。 – 2012-04-20 12:10:22