Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7892161
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 3, 20262026-06-03T06:48:01+00:00 2026-06-03T06:48:01+00:00

There are 3 scenarios in this problem: First possibility: Input: <root> <node id=N1> <fruit

  • 0

There are 3 scenarios in this problem:

First possibility:
Input:

<root>
    <node id="N1">
        <fruit id="1" action="aaa">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>
                    <year>2012</year>
                </attribute>
            </orange>
            <orange id="x" action="change">
                <attribute>
                    <color>Red</color>
                </attribute>
            </orange>
            <orange id="x" action="change">
                <attribute>
                    <color>Blue</color>
                    <condition>good</condition>
                </attribute>
            </orange>
        </fruit>
    </node>
</root>

Expected output:

<root>
    <node id="N1">
        <fruit id="1" action="aaa">
            <orange id="x" action="create">
                <attribute>
                    <color>Blue</color>
                    <year>2012</year>
                    <condition>good</condition>
                </attribute>
            </orange>
        </fruit>
    </node>
</root>

Second Possibility:
Input:

<root>
    <node id="N1">
        <car id="1">
            <bmw id="i" action="change">
                <attribute>
                    <color>Blue</color>
                    <owner>a</owner>
                </attribute>
            </bmw>
            <bmw id="i" action="change">
                <attribute>
                    <color>Yellow</color>
                    <status>avaailable</status>
                </attribute>
            </bmw>
        </car>
    </node>
</root>

Expected Output:

<root>
    <node id="N1">
        <car id="1">
            <bmw id="i" action="change">
                <attribute>
                    <color>Yellow</color>
                    <owner>a</owner>
                    <status>available</status>
                </attribute>
            </bmw>
        </car>
    </node>
</root>

Third Scenario:

<root>
    <node id="N1">
        <car id="1">
            <bmw id="j" action="delete">
                <attribute>
                    <color>Blue</color>
                    <year>2000</year>
                </attribute>
            </bmw>
            <bmw id="j" action="delete">
                <attribute>
                    <color>Pink</color>
                    <status>available</status>
                </attribute>
            </bmw>
        </car>
    </node>
</root>

Expected Output:

<root>
    <node id="N1">
        <car id="1">
            <bmw id="j" action="delete">
                <attribute>
                    <color>Pink</color>
                    <year>2000</year>
                    <status>available</status>
                </attribute>
            </bmw>            
        </car>
    </node>
</root>

Explanation on second and third scenario:

  • Two or more node with ‘action=change’ will be merged into one node with ‘action=change’
  • Two or more node with ‘action=delete’ will be merged into one node with ‘action=delete’
  • while merging, we update we only keep the value from the last node, keep the initial node and add any new additional node with it.

I hope the explanation is clear.

Please advise me on XSLT solution for this problem.
Thank you.

kind regards,
John

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-03T06:48:03+00:00Added an answer on June 3, 2026 at 6:48 am

    Here’s a solution of a different flavor compared to the one I gave you here.

    I figured it would be worth to go step by step. I made an assumption about @actions appearing in a logical order – create first, change next, and remove last. There can be multiple occurrences of the same @action but it wouldn’t be random. Now we’re ready to look at the main logic:

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

    We declare the identity transformation and then intercept it in a few places. We only stop at unique occurrences of a node with the same @id, parent @id, and @action:

    <xsl:template match="node/*/*[a:is-primary(.)]" priority="1">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="attribute" mode="consolidate-most-recent"/>
        </xsl:copy>
    </xsl:template>
    

    We ignore the “duplicates”:

    <xsl:template match="node/*/*[not(a:is-primary(.))]"/>
    

    and also ignore creates following by a change as well as all creates and change followed by a remove.

    <xsl:template match="node/*/*[@action = 'change'][a:preceded-by(., 'create')]" priority="2"/>
    <xsl:template match="node/*/*[@action = 'create' or action='change'][a:followed-by(., 'remove')]" priority="2"/>
    

    When the unique @action not followed by another @action that would make us ignore it is captured, we do a simple thing – collect all attributes of elements with the same @ids ignoring the @action and use their most “recent” values (the ones appearing last in the document order).

    <xsl:template match="attribute" mode="consolidate-most-recent">
        <xsl:copy>
            <xsl:for-each-group 
                        select="/root/node/*/*[a:matches(current()/parent::*, ., 'any')]/attribute/*" 
                        group-by="local-name()">
                <!-- take the last in the document order -->
                <xsl:apply-templates select="current-group()[last()]"/>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    

    That’s it. Now let’s look at the functions that would make it work:

    We have got a key to simplify the lookup

    <xsl:key name="entity" match="/root/node/*/*" use="concat(parent::*/@id, '_', @id, '_', @action)"/>
    

    A function to check whether it’s that unique occurrence of the node (we could add this directly into the template match predicate but since we started with the functions anyway let’s just keep it the same):

    <xsl:function name="a:is-primary" as="xs:boolean">
        <xsl:param name="ctx"/>
        <!-- need to establish "focus"(context) for the key() function to work -->
        <xsl:for-each select="$ctx">
            <xsl:sequence select="generate-id($ctx) = generate-id(key('entity', concat($ctx/parent::*/@id, '_', $ctx/@id, '_', $ctx/@action))[1])"/>
        </xsl:for-each>
    </xsl:function> 
    

    a matches function that will do all kind of comparisons for us (again, can put it all in predicates but this way we’ll keep it nice and clean in the real templates):

    <xsl:function name="a:matches" as="xs:boolean">
        <xsl:param name="src"/>
        <xsl:param name="target"/>
        <!-- can be one of the following:
            'any' - only match the @id(s) and ignore @action
            'same' - match by @id(s) and expect $src/@action to match $target/@action
             a certain value - match by @id(s) and expect @action to match this value
         -->
        <xsl:param name="action"/>
    
        <xsl:value-of select="
                      ($src/local-name() = $target/local-name()) and
                      ($src/parent::*/@id = $target/parent::*/@id) and 
                      ($src/@id = $target/@id) and 
                      (if ($action = 'any') 
                          then true()
                          else if ($action = 'same')
                              then ($target/@action = $src/@action)
                              else ($target/@action = $action))"/>  
    </xsl:function>
    

    And the preceded-by and followed-by syntax sugar on top of the “raw” matches function:

    <xsl:function name="a:preceded-by" as="xs:boolean">
        <xsl:param name="ctx"/>
        <xsl:param name="action"/>
    
        <xsl:value-of select="count($ctx/preceding::*[a:matches($ctx, ., $action)]) > 0"/>
    </xsl:function>
    
    <xsl:function name="a:followed-by" as="xs:boolean">
        <xsl:param name="ctx"/>
        <xsl:param name="action"/>
    
        <xsl:value-of select="count($ctx/following::*[a:matches($ctx, ., $action)]) > 0"/>
    </xsl:function>
    

    SUMMARY

    Here’s a full transformation:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:a="http://a.com">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:key name="entity" match="/root/node/*/*" use="concat(parent::*/@id, '_', @id, '_', @action)"/>
    
        <xsl:function name="a:is-primary" as="xs:boolean">
            <xsl:param name="ctx"/>
            <!-- need to establish "focus"(context) for the key() function to work -->
            <xsl:for-each select="$ctx">
                <xsl:sequence select="generate-id($ctx) = generate-id(key('entity', concat($ctx/parent::*/@id, '_', $ctx/@id, '_', $ctx/@action))[1])"/>
            </xsl:for-each>
        </xsl:function> 
    
        <xsl:function name="a:preceded-by" as="xs:boolean">
            <xsl:param name="ctx"/>
            <xsl:param name="action"/>
    
            <xsl:value-of select="count($ctx/preceding::*[a:matches($ctx, ., $action)]) > 0"/>
        </xsl:function>
    
        <xsl:function name="a:followed-by" as="xs:boolean">
            <xsl:param name="ctx"/>
            <xsl:param name="action"/>
    
            <xsl:value-of select="count($ctx/following::*[a:matches($ctx, ., $action)]) > 0"/>
        </xsl:function>
    
        <xsl:function name="a:matches" as="xs:boolean">
            <xsl:param name="src"/>
            <xsl:param name="target"/>
            <!-- can be one of the following:
                'any' - only match the @id(s) and ignore @action
                'same' - match by @id(s) and expect $src/@action to match $target/@action
                 a certain value - match by @id(s) and expect @action to match this value
             -->
            <xsl:param name="action"/>
    
            <xsl:value-of select="
                          ($src/local-name() = $target/local-name()) and
                          ($src/parent::*/@id = $target/parent::*/@id) and 
                          ($src/@id = $target/@id) and 
                          (if ($action = 'any') 
                              then true()
                              else if ($action = 'same')
                                  then ($target/@action = $src/@action)
                                  else ($target/@action = $action))"/>  
        </xsl:function>
    
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="node/*/*[a:is-primary(.)]" priority="1">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="attribute" mode="consolidate-most-recent"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="attribute" mode="consolidate-most-recent">
            <xsl:copy>
                <xsl:for-each-group 
                            select="/root/node/*/*[a:matches(current()/parent::*, ., 'any')]/attribute/*" 
                            group-by="local-name()">
                    <!-- take the last in the document order -->
                    <xsl:apply-templates select="current-group()[last()]"/>
                </xsl:for-each-group>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="node/*/*[not(a:is-primary(.))]"/>
    
        <!-- assume a remove is never followed by a change or create -->
        <xsl:template match="node/*/*[@action = 'change'][a:preceded-by(., 'create')]" priority="2"/>
        <xsl:template match="node/*/*[@action = 'create' or action='change'][a:followed-by(., 'remove')]" priority="2"/>
    </xsl:stylesheet>
    

    when applied to a document:

    <root>
        <node id="N1">
            <fruit id="1" action="aaa">
                <orange id="x" action="create">
                    <attribute>
                        <color>Orange</color>
                        <year>2012</year>
                    </attribute>
                </orange>
                <orange id="x" action="change">
                    <attribute>
                        <color>Red</color>
                        <something>!!</something>
                    </attribute>
                </orange>
                <orange id="x" action="change">
                    <attribute>
                        <color>Blue</color>
                        <condition>good</condition>
                    </attribute>
                </orange>
                <orange id="x" action="remove">
                    <attribute>
                        <condition>awesome</condition>
                    </attribute>
                </orange>
            </fruit>
        </node>
    </root>
    

    produces the following result:

    <root>
       <node id="N1">
          <fruit id="1" action="aaa">
             <orange id="x" action="remove">
                <attribute>
                   <color>Blue</color>
                   <year>2012</year>
                   <something>!!</something>
                   <condition>awesome</condition>
                </attribute>
             </orange>
          </fruit>
       </node>
    </root>
    

    I hope it’s clear. You can expand on this concept and build yourself a nice library of those reusable functions that you would then use as simple predicates merging your nodes one way or the other. Unlikely to be the most effective way to do the job but at least a clean way to express the solution.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

First let me apologize for the scale of this problem but I'm really trying
Scenario : There is this online questionaire that will be filled in by various
Are there any security exploits that could occur in this scenario: eval(repr(unsanitized_user_input), {__builtins__: None},
Are there any scenarios where more than one Box2D worlds are needed in one
What exactly is Expression<> used for in C#? Are there any scenarios where you
It seems to me that there are two scenarios in which to use JOINs:
I have two distinct scenarios. One, where there is a many to many case,
Let me define the problem first and why a messagequeue has been chosen. I
I've got this - possibly trivial - loop/combinations problem similar to binary combinations. I
My winform application crashes as soon as its been launched. This problem is only

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.