remove deletion on node where it is similar not ex

2019-09-09 11:54发布

问题:

If I have this xml file:

<root> 
        <node id="a">
            <section id="a_1">
               <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
               </item>
            </section>

            <section id="a_2">
               <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
               </item>
            </section>            
        </node>

        <node id="b">
            <section id="b_1">

                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>

                <user id="b_1b">
                    <attribute>a</attribute>
                </user>

            </section>

            <section id="b_1" method="create">

                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>

                <user id="b_1c">
                    <attribute>a</attribute>
                </user>

            </section>

            <section id="b_2">                
                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>

            </section>
        </node>
 </root>

and I want the output to be like this:

    <root> 
        <node id="a">
            <section id="a_1">
               <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
               </item>
            </section>

            <section id="a_2">
               <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
               </item>
            </section>            
        </node>

        <node id="b">
            <section id="b_1">

                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>

                <user id="b_1b">
                    <attribute>a</attribute>
                </user>

            </section>

            <section id="b_1" method="create">

                <user id="b_1c">
                    <attribute>a</attribute>
                </user>

            </section>

            <section id="b_2">                
                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>

            </section>
        </node>
 </root>

As we can see as long as the id is the same it will be considered as one section id even though it has additional method on it. So we delete user id (b_1a) in the second section id (b_1)that has "method create" in it. This really frustrates me and i haven't been able to omit the method. so any help will be greatly appreciated. If we have a look at section id b_2 it also has the same user id b_1 and the same 'John' but we don't remove it because it is in different section id. So basically we compare it based on the section id.

PS: the element can be anything not always user or section but as long as the id is the same.

Thanks very much.

kind regards, John

回答1:

Although I am not entirely clear on the requirements, I think you may want to group elements by their id and the containing section id. This means you may be able to use an xsl:key to look-up elements

<xsl:key 
   name="lookup" 
   match="section//*[@id]" use="concat(ancestor::section[1]/@id, '|', @id)" />

Here we are looking up elements (any element) based on their section ID and their own ID. Then it is just a case of ignoring elements in sections where there is another element with a matching id that exists in the lookup.

<xsl:template 
   match="section//*[@id]
     [generate-id() 
     != generate-id(key('lookup', concat(ancestor::section[1]/@id, '|', @id))[1])]" />

(This is effectively saying, is this element the first element in the look-up. If not, ignore it)

Here is the full XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="lookup" match="section//*[@id]" use="concat(ancestor::section[1]/@id, '|', @id)" />

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="section//*[@id][generate-id() != generate-id(key('lookup', concat(ancestor::section[1]/@id, '|', @id))[1])]" />
</xsl:stylesheet>

When applied to your sample XML, the following is output

<root>
   <node id="a">
      <section id="a_1">
         <item id="0">
            <attribute>
               <color>Red</color>
            </attribute>
         </item>
      </section>
      <section id="a_2">
         <item id="0">
            <attribute>
               <color>Red</color>
            </attribute>
         </item>
      </section>
   </node>
   <node id="b">
      <section id="b_1">
         <user id="b_1a">
            <attribute>
               <name>John</name>
            </attribute>
         </user>
         <user id="b_1b">
            <attribute>a</attribute>
         </user>
      </section>
      <section id="b_1" method="create">
         <user id="b_1c">
            <attribute>a</attribute>
         </user>
      </section>
      <section id="b_2">
         <user id="b_1a">
            <attribute>
               <name>John</name>
            </attribute>
         </user>
      </section>
   </node>
</root>


标签: xml xslt