Solved

use xslt to copy child nodes

Posted on 2007-11-27
15
1,050 Views
Last Modified: 2013-11-18
right now i have the following:
my xml is like:

....
<NODE1>
<CHILDNODE1>
<BLAH>
<BLAH2>
<CHILDNODE2>
</CHILDNODE1>
<CHILDNODE1>
<BLAH>
<BLAH2>
<CHILDNODE2>
<CHILDNODE1>
</NODE1>
....

and then i have this xslt:

<xsl:template match="/">

<xsl:apply-templates/>
</xsl:template>

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

       


<xsl:template match="NODE1">
 
            <xsl:apply-templates select="CHILDNODE1">
                              <xsl:sort select="CHILDNODE2"/>
            </xsl:apply-templates>
                              
 </xsl:template>

which is copying the <CHILDNODE1>'S and its children... but i also want it to copy <NODE1> and its children... hwo can i do that?
0
Comment
Question by:wrynn
  • 6
  • 5
  • 2
  • +1
15 Comments
 
LVL 39

Expert Comment

by:abel
ID: 20356337
Hi Wrynn,

You can do that by completing the matching template for NODE1 and have it copy the node. The fix is to add <xsl:copy> and <xsl:copy-of select="@*" /> right under <xsl:template match="NODE1" />, see code snippet:

HTH,

Cheers,
Abel Braaksma
<xsl:template match="NODE1">

   <xsl:copy>

      <xsl:copy-of select="@*" />

      <xsl:apply-templates select="CHILDNODE1">

          <xsl:sort select="CHILDNODE2"/>

      </xsl:apply-templates>

    </xsl:copy>

</xsl:template>

Open in new window

0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 20356340
this template is copying all nodes,
except the NODE1
That is because you don't have an xsl:copy in the template for NODE1

<xsl:template match="NODE1">
 
            <xsl:apply-templates select="CHILDNODE1">
                              <xsl:sort select="CHILDNODE2"/>
            </xsl:apply-templates>
                             
 </xsl:template>

should be

<xsl:template match="NODE1">
   <xsl:copy>
            <xsl:apply-templates select="CHILDNODE1">
                              <xsl:sort select="CHILDNODE2"/>
            </xsl:apply-templates>
   </xsl:copy>
 </xsl:template>
0
 
LVL 39

Expert Comment

by:abel
ID: 20356356
The reason that it is not copying the NODE1 in your original code is that XSLT works its way through your matches for every node it encounters (the order of which is determined by the <xsl:apply-templates ...>). Then, when it finds multiple matches (i.e., the match="node()" and the match="NODE1") it will choose the most specific of the two.

If you want them *both* to match, you'll have to instruct it to do so. This is easiest in XSLT 2.0, with xsl:next-match. You can also re-apply the current node, but then the problem is one of order: where would you do it and how do you prevent eternal loops? There are ways around it, but in your situation I don't see a compelling reason to break with the traditional "most specific match" rule.

Note that you chose the best way for using XSLT: matching templates. Many users start out with using xsl:for-each because it reminds them of for...next from their other programming environments (Java, C, PHP etc). However, in XSLT, you can define rules of how your output should look like and let the processor decide the order of execution. Which is just what you did. You will find it a very powerful method (i.e.: a catch-all for many nodes, and some exception rules for some other nodes and you are done in most trivial scenarios).

Cheers,
-- Abel --
0
 

Author Comment

by:wrynn
ID: 20360088
these solutions are not working for me.
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 20360192
Well, it is also not really obvious what you need.
Both abel and myself have given you the hints of where to look
Can you show a real piece of your XML (one that is at least wellformed),
a real piece of your XSLT and what you want as a result, that you are not getting

cheers

Geert
0
 

Author Comment

by:wrynn
ID: 20360966
sorry my first example was missing something that is important.  it should be

....
<NODE1>
<ANODE>
<ANODE>
<ANODE>
<CHILDNODE1>
<BLAH>
<BLAH2>
<CHILDNODE2>
</CHILDNODE1>
<ANODE>
<ANODE>
<ANODE>
<CHILDNODE1>
<BLAH>
<BLAH2>
<CHILDNODE2>
<CHILDNODE1>
</NODE1>
....

with my current xslt, it isnt printing the <NODE1> and the <ANODE>'s, but i want it to.  how can i do this?  your examples did not give me the needed solution unfortunately
0
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 250 total points
ID: 20361002
OK, I see,

change your template for NODE1 like this

<xsl:template match="NODE1">
   <xsl:copy>
            <xsl:apply-templates select="*[not(name() = 'CHILDNODE1']">
            <xsl:apply-templates select="CHILDNODE1">
                              <xsl:sort select="CHILDNODE2"/>
            </xsl:apply-templates>
   </xsl:copy>
 </xsl:template>

The problem with this approach is that all the ANODE elements will be outputted first
and all the CHILDNODE1 after that
since you are sorting the CHILDNODE1, I assume it is acceptable that you change some order around

cheers

Geert
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 60

Expert Comment

by:Geert Bormans
ID: 20361010
I need an extra ')' in this line
          <xsl:apply-templates select="*[not(name() = 'CHILDNODE1')]">
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 20361017
XSLT2 syntax is more convenient
          <xsl:apply-templates select="node() except CHILDNODE1">
0
 
LVL 39

Assisted Solution

by:abel
abel earned 250 total points
ID: 20364227
Hi Wrynn,

I like to add a little to Geert's solution. It will copy the nodes as specified by the OP, but it will change the order of the nodes around CHILDNODE1. I.e., all CHILDNODE1 are the last, and the non-CHILDNODE1 nodes are the first when inside the NODE1 node.

If that is a problem, you will have to do a little more (or less) depending on your requirements. It will require a grouping methodology to do that (i.e., sort all sibling CHILDNODE1 that have CHILDNODE2 by the CHILDNODE2 contents and leave the other nodes between the grouped siblings intact).

But I am guessing here.  An alternative solution to the one provided by Geert is below (not that his isn't correct, it works just as well). Instead of guessing what you are after, it'd help us a great deal to show either the real content of your input, or a genuine example of the output you are after based on the input provided above.

In addition, please provide info on what processor you are using, like suggested by Geert, XSLT 2.0 will make for an easier solution.

Cheers,
-- Abel --
<xsl:template match="NODE1">

   <xsl:copy>

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

         <xsl:sort select="CHILDNODE2" />

      </xsl:apply-templates>

   </xsl:copy>

 </xsl:template>

Open in new window

0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 20364412
mmh Abel,

> and leave the other nodes between the grouped siblings intact

your code would still group all the ANODE elements before the CHILDNODE1 elements
since the sort will bring elements lacking a CHILDNODE2 child together
It has a side effect in that if any of the ANODE elements accidentaly has a CHILDNODE2,
it will end up between the CHILDNODE1 elements
making the uncontrolled grouping even worse

but all we are doing here is guessing. I think we have helped as much as we could,
as long as we don't get real XML and a real requirement

all others but abel, ignore the following...
whilst you are around the forum
I am stuck here, maybe you have an idea
http://www.experts-exchange.com/Microsoft/Development/.NET/Q_22979248.html

thanks

Geert
0
 
LVL 39

Expert Comment

by:abel
ID: 20364560
> your code would still group all the ANODE elements before the CHILDNODE1 elements

yes, I know. I am sorry for being unclear about that, I meant to give a similar solution as yours (i.e., without specific grouping), and leave the grouping solution for if/when the OP would provide more information.

> It has a side effect in that if any of the ANODE elements accidentally has a CHILDNODE2,

thanks for pointing that out. It isn't hard to change the sort to provide for that exception, but before we continue, I agree that we should wait until the requirements get clear.

Cheers,
-- Abel --
0
 
LVL 39

Expert Comment

by:abel
ID: 20623538
I have no objections to that
0
 
LVL 1

Expert Comment

by:Computer101
ID: 20659497
Forced accept.

Computer101
EE Admin
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

When you work with shopping cart / ecommerce relates web sites, you need to pass the certain form post details to the payment gateway process page with required details for the products items you give to order. Also you may need to track the ordered…
This article covers the basics of the Sass, which is a CSS extension language. You will learn about variables, mixins, and nesting.
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
HTML5 has deprecated a few of the older ways of showing media as well as offering up a new way to create games and animations. Audio, video, and canvas are just a few of the adjustments made between XHTML and HTML5. As we learned in our last micr…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now