2012-04-02 75 views
2

XSLT新手,但在這裏的帖子中學到了很多東西。但是,我陷入了一個問題。XSLT嵌套查找

我正在使用XSLT爲設備安裝創建報告。輸入XML看起來是這樣的:

<DeviceTypes> 
    <DeviceInfo Model="51473"> 
    <Channels> 
     <ChannelInfo ChannelId="1" IsImplemented="false" SampRateHardware="448" /> 
     <ChannelInfo ChannelId="2" IsImplemented="true" SampRateHardware="224" /> 
    </Channels> 
    </DeviceInfo> 
    <DeviceInfo Model="51474"> 
    <Channels> 
     <ChannelInfo ChannelId="1" IsImplemented="true" SampRateHardware="448" /> 
     <ChannelInfo ChannelId="2" IsImplemented="true" SampRateHardware="224" /> 
    </Channels> 
    </DeviceInfo> 
</DeviceTypes> 
<Installation> 
    <InstalledDevice Serial="597657" Model="51473"> 
    <Channels> 
     <InstalledChannel ChannelId="1" Name="foo" /> 
     <InstalledChannel ChannelId="2" Name="bar" /> 
    </Channels> 
    </InstalledDevice> 
</Installation> 

我只想過程中,如果相應的ChannelInfo有一個「IsImplemented」設置爲true InstallChannel節點。通過「對應」我的意思是我正在尋找具有相同的ChannelId和父節點下相同的模型的ChannelInfo。請注意,具有相同ChannelId的通道可能具有不同的IsImplemented值,具體取決於它們所處的設備。

我一直在使用和key()函數來成功查找,但這種嵌套查找讓我難堪。

感謝,

-Mat

回答

0

我相信使用模板實現更好的可讀性/擴展性:關鍵是使用變量能夠引用兩個型號和渠道ID爲在XPath的InstalledChannel的ChannelInfo節點,所以開始與InstalledDevice,和你的工作方式下的層次結構

<xsl:apply-templates select="//InstalledDevice"/> 

<xsl:template match="//InstalledDevice"> 
    <xsl:variable name="model"> 
     <xsl:value-of select="@Model"/> 
    </xsl:variable> 

    <xsl:for-each select="Channels/InstalledChannel"> 
     <xsl:variable name="channelId"> 
     <xsl:value-of select="@ChannelId"/> 
     </xsl:variable> 

     <xsl:if test="//DeviceInfo[@Model=$model]/Channels/ChannelInfo[@ChannelId=$channelId and @IsImplemented='true']"> 
     Processing Goes Here 
     </xsl:if> 
    </xsl:for-each> 
</xsl:template> 

這樣我們就可以保護我們的模型變量的情況下,我搬到了InstalledChannel加工成相同的模板,並添加了的for-each。這樣,每個InstalledChannel實例都可以單獨檢查是否需要處理,並據此處理。

+0

謝謝。我認爲你很接近。同樣,訣竅是可能有多個ChannelInfo在不同的DeviceInfo下具有相同的ChannelId,並且它們不一定都具有相同的IsImplemented。我會更新示例來說明這一點。 – mek363 2012-04-02 19:13:31

+0

沒問題,相同的一般概念仍然適用,你只需要在樹上開一個更高的點,並且你的xpath變得有點複雜。 (我更新了我的答案)。 – javram 2012-04-02 19:29:03

+0

我認爲現在的問題是,您的變量「channelId」將抓取第一個InstalledChannel,但可能會有多個。我試圖保持我的例子簡單。我會再次更新。謝謝。 – mek363 2012-04-02 21:02:33

0

這樣的事情應該工作。

/Installation/InstalledDevice/Channels/InstalledChannel/[count(/DeviceTypes/DeviceInfo/Channels/ChannelInfo[@ChannelId = @ChannelId and @IsImplemented = 'true') = 1] 
+0

謝謝。我不認爲這會起作用,因爲在不同的DeviceInfo下可能有多個具有相同ChannelId的ChannelInfo,並且它們不一定都具有相同的IsImplemented。 – mek363 2012-04-02 19:08:17

1

下面是一個簡短和簡單(沒有條件語句,不變量無xsl:for-each)溶液中使用的密鑰

<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="kCI-ByIdImpl" match="ChannelInfo" 
    use="concat(@ChannelId, 
       '+', @IsImplemented, 
       '+', ../../@Model)"/> 

<xsl:template match="/*"> 
    <xsl:copy-of select= 
    "Installation/*/* 
     /InstalledChannel 
       [key('kCI-ByIdImpl', 
        concat(@ChannelId, '+true', 
          '+', ../../@Model) 
        ) 
       ]"/> 
</xsl:template> 
</xsl:stylesheet> 

當這個變換所提供的XML片段(包裹成一個單一的頂部施加元件被製成的良好的XML文檔):

<t> 
    <DeviceTypes> 
     <DeviceInfo Model="51473"> 
      <Channels> 
       <ChannelInfo ChannelId="1" IsImplemented="false" SampRateHardware="448" /> 
       <ChannelInfo ChannelId="2" IsImplemented="true" SampRateHardware="224" /> 
      </Channels> 
     </DeviceInfo> 
     <DeviceInfo Model="51474"> 
      <Channels> 
       <ChannelInfo ChannelId="1" IsImplemented="true" SampRateHardware="448" /> 
       <ChannelInfo ChannelId="2" IsImplemented="true" SampRateHardware="224" /> 
      </Channels> 
     </DeviceInfo> 
    </DeviceTypes> 
    <Installation> 
     <InstalledDevice Serial="597657" Model="51473"> 
      <Channels> 
       <InstalledChannel ChannelId="1" Name="foo" /> 
       <InstalledChannel ChannelId="2" Name="bar" /> 
      </Channels> 
     </InstalledDevice> 
    </Installation> 
</t> 

僅想InstalledChannel元件被處理(在這種情況下簡單地複製到輸出):

<InstalledChannel ChannelId="2" Name="bar"/> 

說明:適當使用複合密鑰。