2012-04-17 44 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

相關問題