我正在尝试使用XSL进行一对多映射,而我似乎陷入困境。
我有一个名为Channel的父标记结构,它由1对多的Framework标记组成。每个框架标签又可以由1对多的后端标签组成。这是我的源XML。
<ESBConfig>
<Channels>
<Channel ChannelId="SMS">
<Name>SMS Banking</Name>
<dependentFrameworks>
<FW FrameworkRef="FW001">This is to call FW001</FW>
<FW FrameworkRef="FW002">This is to call FW002</FW>
</dependentFrameworks>
</Channel>
<Channel ChannelId="IBK">
<Name>Internet Banking</Name>
<dependentFrameworks>
<FW FrameworkRef="FW001">This is to call FW001</FW>
<FW FrameworkRef="FW002">This is to call FW002</FW>
</dependentFrameworks>
</Channel>
</Channels>
<Frameworks>
<Framework FrameworkId="FW001">
<Name>Framework 001</Name>
<dependentBackends>
<BE BackendRef="BED001">This is to call BED001</BE>
<BE BackendRef="BED002">This is to call BED002</BE>
</dependentBackends>
</Framework>
<Framework FrameworkId="FW002">
<Name>Framework 002</Name>
<dependentBackends>
<BE BackendRef="BED001">This is to call BED001</BE>
<BE BackendRef="BED002">This is to call BED002</BE>
</dependentBackends>
</Framework>
</Frameworks>
<Backends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</Backends>
</ESBConfig>
在我的XSL中,我使用的是apply-templates和xsl调用模板。但我因为一对多的关系而无法穿越树。这是我想构建的目标XML。
<ESBConfig>
<Channel ChannelId="SMS">
<Name>SMS Banking</Name>
<dependentFrameworks>
<Framework FrameworkId="FW001">
<Name>Framework 1</Name>
<dependentBackends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</dependentBackends>
</Framework>
<Framework FrameworkId="FW002">
<Name>Framework 2</Name>
<dependentBackends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</dependentBackends>
</Framework>
</dependentFrameworks>
</Channel>
</ESBConfig>
这是我到目前为止使用的代码,但我无法迭代给定框架ID的后端数量。任何指针都表示赞赏。感谢
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="ESBConfig">
<xsl:variable name="channelName">
<xsl:value-of select="'SMS'"/>
</xsl:variable>
<xsl:variable name="frameworkRef">
<xsl:value-of select="/ESBConfig/Channels/Channel[@ChannelId=$channelName]/dependentFrameworks/FW/@FrameworkRef"/>
</xsl:variable>
<xsl:variable name="backendRef">
<xsl:value-of select="/ESBConfig/Frameworks/Framework[@FrameworkId=$frameworkRef]/dependentBackends/BE/@BackendRef"/>
</xsl:variable>
<tr>
<Level2>
<xsl:element name="channelName">
<xsl:value-of select="$channelName"/>
</xsl:element>
<channelName>
<xsl:value-of select="'SMS'"/>
</channelName>
</Level2>
<Level1>
<xsl:element name="frameworkRef">
<xsl:value-of select="$frameworkRef"/>
</xsl:element>
<framework>
<xsl:copy-of select="/ESBConfig/Frameworks/Framework[@FrameworkId=$frameworkRef]"/>
</framework>
</Level1>
<Level0>
<xsl:variable name="snippet">
<xsl:copy-of select="/ESBConfig/Frameworks/Framework[@FrameworkId=$frameworkRef]/dependentBackends/BE"/>
</xsl:variable>
<xsl:for-each select="$snippet/BE">
<xsl:variable name="temp">
<xsl:value-of select="@BackendRef"/>
</xsl:variable>
<Bref>
<xsl:value-of select="$temp"/>
</Bref>
</xsl:for-each>
</Level0>
</tr>
</xsl:template>
<xsl:template match="/ESBConfig/Backends">
<xsl:param name="bid"/>
<xsl:copy-of select="Backend[@BackendId=$bid]"/>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:2)
使用两个键,第一个键是<xsl:key name="fw" match="Framework" use="@FrameworkId"/>
,然后在与Channel
匹配的模板中使用它来处理<xsl:apply-templates select="key('fw', dependentFramework/Framework/@FrameworkRef)"/>
。您可以使用相同的方法来遵循其他交叉引用。
答案 1 :(得分:2)
这是Martin Honnen谈论的方法的一个例子。它与您的示例XSLT(创建tr
&{39}和Level#
元素)有很大不同,但匹配所需的输出*。
*输出包含所有Channel
个元素和Channels
包装元素,其中请求的输出仅包含SMS
个通道。如果您需要将输出限制为单个频道,我建议您在选择中为xsl:param
添加Channel
和谓词。如果您想要更新的示例,请与我们联系。
XML输入
<ESBConfig>
<Channels>
<Channel ChannelId="SMS">
<Name>SMS Banking</Name>
<dependentFrameworks>
<FW FrameworkRef="FW001">This is to call FW001</FW>
<FW FrameworkRef="FW002">This is to call FW002</FW>
</dependentFrameworks>
</Channel>
<Channel ChannelId="IBK">
<Name>Internet Banking</Name>
<dependentFrameworks>
<FW FrameworkRef="FW001">This is to call FW001</FW>
<FW FrameworkRef="FW002">This is to call FW002</FW>
</dependentFrameworks>
</Channel>
</Channels>
<Frameworks>
<Framework FrameworkId="FW001">
<Name>Framework 001</Name>
<dependentBackends>
<BE BackendRef="BED001">This is to call BED001</BE>
<BE BackendRef="BED002">This is to call BED002</BE>
</dependentBackends>
</Framework>
<Framework FrameworkId="FW002">
<Name>Framework 002</Name>
<dependentBackends>
<BE BackendRef="BED001">This is to call BED001</BE>
<BE BackendRef="BED002">This is to call BED002</BE>
</dependentBackends>
</Framework>
</Frameworks>
<Backends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</Backends>
</ESBConfig>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="frameworks" match="Framework" use="@FrameworkId"/>
<xsl:key name="backends" match="Backend" use="@BackendId"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="@*|Channels"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FW">
<xsl:apply-templates select="key('frameworks',@FrameworkRef)"/>
</xsl:template>
<xsl:template match="BE">
<xsl:apply-templates select="key('backends',@BackendRef)"/>
</xsl:template>
</xsl:stylesheet>
XML输出
<ESBConfig>
<Channels>
<Channel ChannelId="SMS">
<Name>SMS Banking</Name>
<dependentFrameworks>
<Framework FrameworkId="FW001">
<Name>Framework 001</Name>
<dependentBackends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</dependentBackends>
</Framework>
<Framework FrameworkId="FW002">
<Name>Framework 002</Name>
<dependentBackends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</dependentBackends>
</Framework>
</dependentFrameworks>
</Channel>
<Channel ChannelId="IBK">
<Name>Internet Banking</Name>
<dependentFrameworks>
<Framework FrameworkId="FW001">
<Name>Framework 001</Name>
<dependentBackends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</dependentBackends>
</Framework>
<Framework FrameworkId="FW002">
<Name>Framework 002</Name>
<dependentBackends>
<Backend BackendId="BED001">
<Name>Backend 1</Name>
</Backend>
<Backend BackendId="BED002">
<Name>Backend 2</Name>
</Backend>
</dependentBackends>
</Framework>
</dependentFrameworks>
</Channel>
</Channels>
</ESBConfig>
答案 2 :(得分:0)
您可以使用标签。例如:
<xsl:for-each select="Channel">
<!-- Your code here -->
</xsl:for-each>
for-each的工作原理与任何其他编程语言一样: 它选择select属性中Tag的每个出现位置,然后为每个属性执行以下操作。