首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >XSLT,展平递归函数的结果

XSLT,展平递归函数的结果
EN

Stack Overflow用户
提问于 2013-12-10 01:04:43
回答 1查看 284关注 0票数 1

我正在尝试删除在xml文件中定义的消息中没有直接或间接使用的节点。“链接”的定义如下。

我正在尝试处理(修复) xml文档,以提取与我感兴趣的消息组件相匹配的组件。文档结构类似于

代码语言:javascript
复制
<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>

因此,我已经设法识别了我所拥有的消息中的组。我还能够递归地获得被其他组件引用的组件。我想要扁平化返回的组件节点,并将它们转换为一个唯一的集合,这就是我的方法失败的地方。

代码语言:javascript
复制
 <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还没有到允许我适应这些解决方案的阶段,所以有人能提供帮助吗?

谢谢。

嗨,我还应该注意到会有不止一条消息。这样做的目的是删除文档内的消息标记中未引用的组(以及最终的其他字段)。然后,输出最终应该是

代码语言:javascript
复制
<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文档的末尾有许多字段,如下所示

代码语言:javascript
复制
<fix>
    <messages>
        <message/>
    <messages>
    groups>
        <group/>
    <groups>
    <fields>
        <field name="abc"/>
        <field name="bcd"/>
    <fields>
</fix>

我尝试只保留其名称与任何消息或组位置中的字段匹配,或者与gropu或组件名称匹配的字段。我能够保留大部分,但不是全部,最终得到了一个令人讨厌的嵌套选择结构。有没有人能提供更多的建议?谢谢。

例如,我正在尝试添加以下内容:

代码语言:javascript
复制
<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>

我认为它应该与使用消息的组中使用的字段相匹配。然而,这并没有发生。

EN

回答 1

Stack Overflow用户

发布于 2013-12-10 06:02:34

首先,我将从身份模板开始

代码语言:javascript
复制
<xsl:template match="@*|node()" name="identity">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>

就这一点而言,它会按原样复制所有节点。这意味着你采取的方法不是试图找出你需要复制的东西,而是找出你不需要复制的东西。

为了帮助查找组件,我将定义两个键;一个用于查找原始的"message“组件,另一个用于查找出现在"group”下的组件。

代码语言:javascript
复制
<xsl:key name="c1" match="message/component" use="@name" />
<xsl:key name="c2" match="group/component" use="@name" />

现在,您只关心组件没有被"message“直接引用的情况。

代码语言:javascript
复制
<xsl:template match="components/component[not(key('c1', @name))]">

在此过程中,您将开始使用递归模板检查此“组件”元素是否在其他地方被引用。

代码语言:javascript
复制
  <xsl:variable name="IsUsed">
     <xsl:apply-templates select="key('c2', @name)" mode="IsUsed"/>
  </xsl:variable>

虽然您可以为这个"IsUsed“检查使用一个模板,但我将用两个模板来完成:

代码语言:javascript
复制
<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:

代码语言:javascript
复制
<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>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20476328

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档