我正在尝试删除在xml文件中定义的消息中没有直接或间接使用的节点。“链接”的定义如下。
我正在尝试处理(修复) xml文档,以提取与我感兴趣的消息组件相匹配的组件。文档结构类似于
<fix>
<messages>
<message name="myMessage1">
<field name="abc"/>
<component name="component1"/>
<component name="component2"/>
</message>
<message name="myMessage2">
<field name="hello"/>
<component name="component1"/>
</message>
</messages>
<components>
<component name="component1">
</component>
<component name="component2">
<group name="agroup">
<field name="afield"/>
<component name="component3"/>
</group>
</component>
<component name="component3">
</component>
<component name="component4">
</component>
<component name="component5">
</component>
<component name="component6">
<group name="agroup">
<field name="afield"/>
<component name="component3"/>
<component name="component4"/>
</group>
</component>
</components>
</fix>因此,我已经设法识别了我所拥有的消息中的组。我还能够递归地获得被其他组件引用的组件。我想要扁平化返回的组件节点,并将它们转换为一个唯一的集合,这就是我的方法失败的地方。
<xsl:template match="components">
<nodes>
<xsl:for-each select="/fix/messages/message/component">
<xsl:call-template name="findGroups">
<xsl:with-param name="groups" select="@name"/>
</xsl:call-template>
</xsl:for-each>
</nodes>
</xsl:template>
<xsl:template name="findGroups">
<xsl:param name="groups" />
<print>
<xsl:value-of select="$groups"></xsl:value-of>
</print>
<xsl:for-each select="/fix/components/component[@name=$groups]">
<here>
<xsl:call-template name="findGroups">
<xsl:with-param name="groups" select="group/component/@name"/>
</xsl:call-template>
</here>
</xsl:for-each>
</xsl:template>我已经看到过使用键或其他技术来解决类似问题的解决方案,但是我的xslt/xpath还没有到允许我适应这些解决方案的阶段,所以有人能提供帮助吗?
谢谢。
嗨,我还应该注意到会有不止一条消息。这样做的目的是删除文档内的消息标记中未引用的组(以及最终的其他字段)。然后,输出最终应该是
<fix>
<messages>
<message name="myMessage1">
<field name="abc"/>
<component name="component1"/>
<component name="component2"/>
</message>
<message name="myMessage2">
<field name="hello"/>
<component name="component1"/>
</message>
</messages>
<components>
<component name="component1">
</component>
<component name="component2">
<group name="agroup">
<field name="afield"/>
<component name="component3"/>
</group>
</component>
<component name="component3"/>
</component>
</components>
</fix>注意-从消息节点最终无法访问的component4和其他标记已被删除。
好了,上面的问题已经回答了,我现在遇到了一个额外的问题。实际上,xml文档的末尾有许多字段,如下所示
<fix>
<messages>
<message/>
<messages>
groups>
<group/>
<groups>
<fields>
<field name="abc"/>
<field name="bcd"/>
<fields>
</fix>我尝试只保留其名称与任何消息或组位置中的字段匹配,或者与gropu或组件名称匹配的字段。我能够保留大部分,但不是全部,最终得到了一个令人讨厌的嵌套选择结构。有没有人能提供更多的建议?谢谢。
例如,我正在尝试添加以下内容:
<xsl:key name="c3" match="message/field" use="@name" />
<xsl:key name="c4" match="group/field" use="@name" />
<xsl:key name="c5" match="group" use="@name" />
<xsl:key name="c6" match="component" use="@name" />
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="fields/field[not(key('c3', @name))]">
<xsl:variable name="IsUsed">
<xsl:apply-templates select="key('c4', @name)"/>
<!-- <xsl:apply-templates select="key('c5', @name)"/>
<xsl:apply-templates select="key('c6', @name)"/> -->
</xsl:variable>
<xsl:if test="$IsUsed != ''">
<xsl:call-template name="identity" />
</xsl:if>
</xsl:template>
<xsl:template match="group/field[not(key('c1', ../../@name))]" mode="IsUsed">
<xsl:apply-templates select="key('c2', ../../@name)" mode="IsUsed"/>
</xsl:template>
<xsl:template match="group/field[key('c1', ../../@name)]" mode="IsUsed">
<xsl:text>1</xsl:text>
</xsl:template>我认为它应该与使用消息的组中使用的字段相匹配。然而,这并没有发生。
发布于 2013-12-10 06:02:34
首先,我将从身份模板开始
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>就这一点而言,它会按原样复制所有节点。这意味着你采取的方法不是试图找出你需要复制的东西,而是找出你不需要复制的东西。
为了帮助查找组件,我将定义两个键;一个用于查找原始的"message“组件,另一个用于查找出现在"group”下的组件。
<xsl:key name="c1" match="message/component" use="@name" />
<xsl:key name="c2" match="group/component" use="@name" />现在,您只关心组件没有被"message“直接引用的情况。
<xsl:template match="components/component[not(key('c1', @name))]">在此过程中,您将开始使用递归模板检查此“组件”元素是否在其他地方被引用。
<xsl:variable name="IsUsed">
<xsl:apply-templates select="key('c2', @name)" mode="IsUsed"/>
</xsl:variable>虽然您可以为这个"IsUsed“检查使用一个模板,但我将用两个模板来完成:
<xsl:template match="group/component[key('c1', ../../@name)]" mode="IsUsed">
<xsl:text>1</xsl:text>
</xsl:template>
<xsl:template match="group/component[not(key('c1', ../../@name))]" mode="IsUsed">
<xsl:apply-templates select="key('c2', ../../@name)" mode="IsUsed"/>
</xsl:template>因此,当父组件被"message“使用时,第一个模板将匹配,如果是,则返回"1",否则第二个模板将匹配,并进行递归调用以继续匹配。
试试这个XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="c1" match="message/component" use="@name" />
<xsl:key name="c2" match="group/component" use="@name" />
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="components/component[not(key('c1', @name))]">
<xsl:variable name="IsUsed">
<xsl:apply-templates select="key('c2', @name)" mode="IsUsed"/>
</xsl:variable>
<xsl:if test="$IsUsed != ''">
<xsl:call-template name="identity" />
</xsl:if>
</xsl:template>
<xsl:template match="group/component[not(key('c1', ../../@name))]" mode="IsUsed">
<xsl:apply-templates select="key('c2', ../../@name)" mode="IsUsed"/>
</xsl:template>
<xsl:template match="group/component[key('c1', ../../@name)]" mode="IsUsed">
<xsl:text>1</xsl:text>
</xsl:template>
</xsl:stylesheet>https://stackoverflow.com/questions/20476328
复制相似问题