Remove parent element if there are no children

Discussion in 'XML' started by CI, Apr 13, 2007.

  1. CI

    CI Guest

    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" xmlns:xsl="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>
    <xsl:eek:therwise>
    <xsl:copy-of select="."/>
    </xsl:eek:therwise>
    </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
     
    CI, Apr 13, 2007
    #1
    1. Advertising

  2. > 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
     
    Joseph Kesselman, Apr 13, 2007
    #2
    1. Advertising

  3. > <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
     
    Joseph Kesselman, Apr 14, 2007
    #3
  4. CI

    CI Guest

    On Apr 13, 4:59 pm, Joseph Kesselman <>
    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"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput 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
     
    CI, Apr 14, 2007
    #4
  5. 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
     
    Joe Kesselman, Apr 14, 2007
    #5
  6. "Joe Kesselman" <> wrote in message
    news:...
    > 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! :eek:)


    Cheers,
    Dimitre Novatchev
     
    Dimitre Novatchev, Apr 14, 2007
    #6
  7. CI

    Guest

    On Apr 14, 3:46 am, "CI" <> wrote:
    > On Apr 13, 4:59 pm, Joseph Kesselman
    > <> 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"
    xmlns:xsl="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
     
    , Apr 14, 2007
    #7
  8. CI

    Guest

    On Apr 14, 10:22 am, wrote:
    > On Apr 14, 3:46 am, "CI" <> wrote:
    >
    > > On Apr 13, 4:59 pm, Joseph Kesselman
    > > <> 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"
    xmlns:xsl="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
     
    , Apr 14, 2007
    #8
  9. 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
     
    Joe Kesselman, Apr 14, 2007
    #9
  10. Dimitre Novatchev wrote:
    > Of course, and this is exactly what the OP wanted! :eek:)


    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
     
    Joe Kesselman, Apr 14, 2007
    #10
  11. "Joe Kesselman" <> wrote in message
    news:...
    > 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.



    C'mon people,

    Do you know how much additional memory such a solution may use? Twice the
    memory of one-pass solution.

    Where possible, do try to "fuse" (the term is "fusion" or "deforestation") a
    pipeline of passes into a single pass.

    And, of course, I am not rediscovering the wheel here...


    Cheers,
    Dimitre Novatchev.
     
    Dimitre Novatchev, Apr 14, 2007
    #11
  12. Dimitre Novatchev wrote:
    > Do you know how much additional memory such a solution may use? Twice the
    > memory of one-pass solution.


    It may, or it may not, depending on the internal data model of the
    processor. And for simple input documents, that really may not matter.

    In fact, what I'd do if taking this approach was to do two-pass
    processing only locally, on the element which requires it -- so the
    overhead is both smaller and transient.

    It can be taken further... but see first paragraph; before spending too
    much effort on optimization, consider whether the improvement is worth
    the effort. Learn to do it right, but also learn when good enough is
    good enough.


    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
     
    Joe Kesselman, Apr 14, 2007
    #12
  13. CI

    roy axenov Guest

    On Apr 14, 6:26 pm, "Dimitre Novatchev"
    <> wrote:
    > "Joe Kesselman" <> wrote in
    > message
    > news:...
    > > 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.

    >
    > Do you know how much additional memory such a solution
    > may use? Twice the memory of one-pass solution.
    >
    > Where possible, do try to "fuse" (the term is "fusion" or
    > "deforestation") a pipeline of passes into a single pass.


    I don't know about you, but premature optimization is a sin
    in my book. Go for clarity and neatness first, deal with
    performance issues as they arise.

    --
    roy axenov
     
    roy axenov, Apr 14, 2007
    #13
  14. roy axenov wrote:
    > I don't know about you, but premature optimization is a sin
    > in my book. Go for clarity and neatness first, deal with
    > performance issues as they arise.


    Especially when still teaching basic concepts.

    Steve Boies: "Make it work, make it good, make it great."
    (Chorus response: "In that order!")


    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
     
    Joe Kesselman, Apr 14, 2007
    #14
  15. "Joe Kesselman" <> wrote in message
    news:...
    > roy axenov wrote:
    >> I don't know about you, but premature optimization is a sin
    >> in my book. Go for clarity and neatness first, deal with
    >> performance issues as they arise.

    >
    > Especially when still teaching basic concepts.
    >
    > Steve Boies: "Make it work, make it good, make it great."
    > (Chorus response: "In that order!")
    >
    >
    > --
    > () ASCII Ribbon Campaign | Joe Kesselman
    > /\ Stamp out HTML e-mail! | System architexture and kinetic poetry


    Yes, and following all these recommendations I'd still prefer the most
    compact and elegant solution (sorry, it happens to be the one I proposed
    ) )

    I didn't spend any time trying to optimize -- just chose the most *natural*
    solution, which for XSLT happens to be overriding the identity rule -- and
    this is so for more than 90% of all cases.


    Cheers,
    Dimitre Novatchev.
     
    Dimitre Novatchev, Apr 14, 2007
    #15
  16. Dimitre Novatchev wrote:
    > I didn't spend any time trying to optimize -- just chose the most *natural*
    > solution, which for XSLT happens to be overriding the identity rule -- and
    > this is so for more than 90% of all cases.


    I agree that this is the core starting point for most XSLT design.



    --
    () ASCII Ribbon Campaign | Joe Kesselman
    /\ Stamp out HTML e-mail! | System architexture and kinetic poetry
     
    Joe Kesselman, Apr 14, 2007
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Joel Lindsey
    Replies:
    1
    Views:
    1,520
    Steve W. Jackson
    Sep 22, 2003
  2. Matt
    Replies:
    2
    Views:
    868
    Ben Edgington
    Oct 12, 2004
  3. Replies:
    4
    Views:
    2,598
  4. Dave Mathew
    Replies:
    0
    Views:
    873
    Dave Mathew
    Oct 6, 2008
  5. okey
    Replies:
    2
    Views:
    172
    David Mark
    May 24, 2009
Loading...

Share This Page