Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > XML > Remove parent element if there are no children

Reply
Thread Tools

Remove parent element if there are no children

 
 
CI
Guest
Posts: n/a
 
      04-13-2007
I have the following XML file

<Book>
<Chapters>
<Chapter number="1"/>
<Chapter number="2"/>
</Chapters>
<Colors>
<Color RGB="255"/>
<Color RGB="211" name="Red"/>
<Color name="Yellow"/>
<Color RGB="127"/>
</Colors>
</Book>

I want to get a tree with the <Color> elements that don't have RGB
attribute:

So I came up with this XSLT sheet.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlnssl="http://www.w3.org/1999/XSL/
Transform">


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


<xsl:template match="Color">

<xsl:choose>
<xsl:when test="@RGB">

</xsl:when>
<xsltherwise>
<xsl:copy-of select="."/>
</xsltherwise>
</xsl:choose>

</xsl:template>

</xsl:stylesheet>

It works correctly, but if in my XML file all the <Color> elements
have RGB attribute the resulted tree
contains empty <Colors></Colors> node.

Anyone had an idea how to conditionally remove it?

Regards,

Michael

 
Reply With Quote
 
 
 
 
Joseph Kesselman
Guest
Posts: n/a
 
      04-13-2007
> Anyone had an idea how to conditionally remove it?

Adding a check for no-children-exist to your RGB-attribute-exists test
ought to do it, right?




--
Joe Kesselman / Beware the fury of a patient man. -- John Dryden
 
Reply With Quote
 
 
 
 
Joseph Kesselman
Guest
Posts: n/a
 
      04-13-2007
> <Colors>
> <Color RGB="255"/>
> <Color RGB="211" name="Red"/>
> <Color name="Yellow"/>
> <Color RGB="127"/>
> </Colors>


> It works correctly, but if in my XML file all the <Color> elements
> have RGB attribute the resulted tree
> contains empty <Colors></Colors> node.
>
> Anyone had an idea how to conditionally remove it?


Don't think about "removing", think about "not copying".

You want to copy the <Colors> element only if it contains something
other than a <Color> element with an RGB attribute.

Complication: Removing the <Color> elements from the above example does
NOT make <Colors> empty, even if you remove Yellow -- because it still
contains the whitespace text nodes between the elements.

It's possible to solve this in a single pass, but I think it's going to
be ugly. You may want to think about making it simpler by running a
second stylesheet that removes <Colors> elements that contain only
whitespace... or, if you're willing to rely on the nodeset extensions,
running two passes within a single stylesheet by first styling part or
all of the document into a variable and then styling from the variable
to your actual output. Look for examples of use of the exslt:node-set
extension for information about how to do this.




--
Joe Kesselman / Beware the fury of a patient man. -- John Dryden
 
Reply With Quote
 
CI
Guest
Posts: n/a
 
      04-14-2007
On Apr 13, 4:59 pm, Joseph Kesselman <(E-Mail Removed)>
wrote:
> > <Colors>
> > <Color RGB="255"/>
> > <Color RGB="211" name="Red"/>
> > <Color name="Yellow"/>
> > <Color RGB="127"/>
> > </Colors>
> > It works correctly, but if in my XML file all the <Color> elements
> > have RGB attribute the resulted tree
> > contains empty <Colors></Colors> node.

>
> > Anyone had an idea how to conditionally remove it?

>
> Don't think about "removing", think about "not copying".
>
> You want to copy the <Colors> element only if it contains something
> other than a <Color> element with an RGB attribute.
>
> Complication: Removing the <Color> elements from the above example does
> NOT make <Colors> empty, even if you remove Yellow -- because it still
> contains the whitespace text nodes between the elements.
>
> It's possible to solve this in a single pass, but I think it's going to
> be ugly. You may want to think about making it simpler by running a
> second stylesheet that removes <Colors> elements that contain only
> whitespace... or, if you're willing to rely on the nodeset extensions,
> running two passes within a single stylesheet by first styling part or
> all of the document into a variable and then styling from the variable
> to your actual output. Look for examples of use of the exslt:node-set
> extension for information about how to do this.
>
> --
> Joe Kesselman / Beware the fury of a patient man. -- John Dryden


Thanks Joe, I appreciate it.

I posted this problem to another group and Dimitre Novatchev
suggested the following stylesheet:

------------------------------------------------------------------------------------------
<xsl:stylesheet version="1.0"
xmlnssl="http://www.w3.org/1999/XSL/Transform">
<xslutput omit-xml-declaration="yes" indent="yes"/>

<xsl:strip-space elements="*"/>

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

<xsl:template match="Colors[not(Color[not(@RGB)])]"/>
<xsl:template match="Color[@RGB]"/>
</xsl:stylesheet>
------------------------------------------------------------------------------



Regards,

Michael




 
Reply With Quote
 
Joe Kesselman
Guest
Posts: n/a
 
      04-14-2007
CI wrote:
> <xsl:template match="Colors[not(Color[not(@RGB)])]"/>


OK, that will certainly discard <Colors> elements that do not contain a
<Color> which does not have the RGB attribute. If the only things that
will be in <Colors> is <Color> elements and whitespace, that should
work. If there's anything else which might appear there, you may wind up
deleting some elements that you wanted to keep.

--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
 
Reply With Quote
 
Dimitre Novatchev
Guest
Posts: n/a
 
      04-14-2007

"Joe Kesselman" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> CI wrote:
>> <xsl:template match="Colors[not(Color[not(@RGB)])]"/>

>
> OK, that will certainly discard <Colors> elements that do not contain a
> <Color> which does not have the RGB attribute. If the only things that
> will be in <Colors> is <Color> elements and whitespace, that should work.


Of course, and this is exactly what the OP wanted! )


Cheers,
Dimitre Novatchev


 
Reply With Quote
 
p.lepin@ctncorp.com
Guest
Posts: n/a
 
      04-14-2007
On Apr 14, 3:46 am, "CI" <(E-Mail Removed)> wrote:
> On Apr 13, 4:59 pm, Joseph Kesselman
> <(E-Mail Removed)> wrote:


[...]

> > > It works correctly, but if in my XML file all the
> > > <Color> elements have RGB attribute the resulted tree
> > > contains empty <Colors></Colors> node. Anyone had an
> > > idea how to conditionally remove it?

>
> > Don't think about "removing", think about "not
> > copying".


[...]

> I posted this problem to another group and Dimitre
> Novatchev suggested the following stylesheet:
>
> <xsl:template match="Colors[not(Color[not(@RGB)])]"/>
> <xsl:template match="Color[@RGB]"/>


This is a very clean and neat solution,--which is hardly
surprising,--but I always cringe a bit when I have to
express the same thing twice in the code. The following
looks a bit scarier, but has what counts as virtue with me:
it's re-uses the condition that both your rules are
dependent upon:

<xsl:stylesheet version="1.0"
xmlnssl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Colors">
<xsl:variable name="color-elements"
select="Color[not(@RGB)]"/>
<xsl:if test="$color-elements">
<xsl:copy>
<xsl:apply-templates select="$color-elements"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

YMMV.

--
Pavel Lepin

 
Reply With Quote
 
p.lepin@ctncorp.com
Guest
Posts: n/a
 
      04-14-2007
On Apr 14, 10:22 am, (E-Mail Removed) wrote:
> On Apr 14, 3:46 am, "CI" <(E-Mail Removed)> wrote:
>
> > On Apr 13, 4:59 pm, Joseph Kesselman
> > <(E-Mail Removed)> wrote:

>
> > > > It works correctly, but if in my XML file all the
> > > > <Color> elements have RGB attribute the resulted
> > > > tree contains empty <Colors></Colors> node. Anyone
> > > > had an idea how to conditionally remove it?

>
> > > Don't think about "removing", think about "not
> > > copying".

>
> > I posted this problem to another group and Dimitre
> > Novatchev suggested the following stylesheet:

>
> This is a very clean and neat solution,--which is hardly
> surprising,--but I always cringe a bit when I have to
> express the same thing twice in the code. The following
> looks a bit scarier, but has what counts as virtue with me:
> it's re-uses the condition that both your rules are
> dependent upon:


On a side note, XSLT2 is bliss:

<xsl:stylesheet version="2.0"
xmlnssl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="post-pass-1">
<xsl:apply-templates mode="pass-1"/>
</xsl:variable>
<xsl:apply-templates select="$post-pass-1"
mode="pass-2"/>
</xsl:template>
<xsl:template match="@*|node()" mode="pass-1">
<xsl:copy>
<xsl:apply-templates select="@*|node()"
mode="pass-1"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Color[@RGB]" mode="pass-1"/>
<xsl:template match="@*|node()" mode="pass-2">
<xsl:copy>
<xsl:apply-templates select="@*|node()"
mode="pass-2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Colors[not(*)]" mode="pass-2"/>
</xsl:stylesheet>

--
Pavel Lepin

 
Reply With Quote
 
Joe Kesselman
Guest
Posts: n/a
 
      04-14-2007
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> On a side note, XSLT2 is bliss:


A minor change, but a good one: XSLT removed the distinction between
Result Tree Fragments and Node Sets (both are now grouped together as
Temporary Trees), so one doesn't need the node-set extension to convert
the former into the latter.

Outside of that, this is the same two-past solution I suggested.

--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
 
Reply With Quote
 
Joe Kesselman
Guest
Posts: n/a
 
      04-14-2007
Dimitre Novatchev wrote:
> Of course, and this is exactly what the OP wanted! )


Granted. But I tend to practice defensive programming, so I look for the
maximally robust solution...


--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
If a class Child inherits from Parent, how to implementChild.some_method if Parent.some_method() returns Parent instance ? metal Python 8 10-30-2009 10:31 AM
element.children.length v/s element.childNodes.length okey Javascript 2 05-24-2009 04:36 PM
Remove parent element with a child element matching a given rule patrizio.trinchini@googlemail.com XML 4 08-22-2006 11:31 AM
Possible to traverse the children of an element without specifying child element names? Matt XML 2 10-12-2004 08:23 AM
per the active schema, the element <BR> must be included within a parent element MSNews ASP .Net 1 04-22-2004 04:45 PM



Advertisments