我正在尝试删除未在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或组件名称。我能够保留最多,但不是全部,并且最终得到了令人讨厌的嵌套选择结构。有人可以提供更多指示吗?感谢。
e.g。我正在尝试添加以下内容: -
<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>
我认为应该匹配使用消息的组中使用的字段。但是,这种情况并没有发生。
答案 0 :(得分:1)
首先,我将从身份模板开始
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
就此而言,这会按原样复制所有节点。这意味着您采取的方法不是试图弄清楚您需要复制的内容,而是找出您不需要复制的内容。
为了帮助查找组件,我将定义两个键;一个用于查找原始“消息”组件,另一个用于查找“组”下出现的组件
<xsl:key name="c1" match="message/component" use="@name" />
<xsl:key name="c2" match="group/component" use="@name" />
现在,您只担心组件未被“消息”
直接引用的情况<xsl:template match="components/component[not(key('c1', @name))]">
在此范围内,您将使用递归模板检查此“component”元素是否在其他地方被引用。
<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>
因此,当父组件被“消息”使用时,第一个模板将匹配,如果是,则返回“1”,否则第二个模板将匹配,并进行递归调用以保持匹配。 / p>
试试这个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>