Recursively remove nodes when children are empty in XSLT












0















I am new to using xsl and I am not sure how to remove specific parent nodes and all their children, if all are empty. I think the answer shown in this link is what I need, but I am not sure how to apply this to a specific node instead of the whole stylesheet.



Using what is in that question, I have expanded it ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz></buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds>
</sounds>
</farm>


How can I just eliminate <sounds> and all of its children (if they are all empty) while leaving empty nodes like foo, bar, and baz. The requirements for the xml I am producing needs to have certain tags present even if they are blank, but some need to be removed if they are blank.



To go even further, if what I had is ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz>"zzzz"</buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds> <!-- Fixed by edit -->
</sounds>
</farm>


In this example,<sounds>, <moo>, <meow>, and <buzz> would need to stay since <buzz> has a value, but <birds> and its children would need to be removed.



This seems so complicated to me, I am not sure what the simplest way to do this would be.



Thank you so much for your guidance, as I feel dizzy from going in so many circles!










share|improve this question

























  • I don't understand you question. Is there a list of elements you want to keep even if they are empty? If so, how would it look in the given examples? -- BTW, cluck is not really empty - so I guess you want to consider whitespace-only as empty?

    – michael.hor257k
    Nov 21 '18 at 18:06











  • Also tell us which version of XSLT your processor supports.

    – michael.hor257k
    Nov 21 '18 at 18:07
















0















I am new to using xsl and I am not sure how to remove specific parent nodes and all their children, if all are empty. I think the answer shown in this link is what I need, but I am not sure how to apply this to a specific node instead of the whole stylesheet.



Using what is in that question, I have expanded it ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz></buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds>
</sounds>
</farm>


How can I just eliminate <sounds> and all of its children (if they are all empty) while leaving empty nodes like foo, bar, and baz. The requirements for the xml I am producing needs to have certain tags present even if they are blank, but some need to be removed if they are blank.



To go even further, if what I had is ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz>"zzzz"</buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds> <!-- Fixed by edit -->
</sounds>
</farm>


In this example,<sounds>, <moo>, <meow>, and <buzz> would need to stay since <buzz> has a value, but <birds> and its children would need to be removed.



This seems so complicated to me, I am not sure what the simplest way to do this would be.



Thank you so much for your guidance, as I feel dizzy from going in so many circles!










share|improve this question

























  • I don't understand you question. Is there a list of elements you want to keep even if they are empty? If so, how would it look in the given examples? -- BTW, cluck is not really empty - so I guess you want to consider whitespace-only as empty?

    – michael.hor257k
    Nov 21 '18 at 18:06











  • Also tell us which version of XSLT your processor supports.

    – michael.hor257k
    Nov 21 '18 at 18:07














0












0








0








I am new to using xsl and I am not sure how to remove specific parent nodes and all their children, if all are empty. I think the answer shown in this link is what I need, but I am not sure how to apply this to a specific node instead of the whole stylesheet.



Using what is in that question, I have expanded it ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz></buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds>
</sounds>
</farm>


How can I just eliminate <sounds> and all of its children (if they are all empty) while leaving empty nodes like foo, bar, and baz. The requirements for the xml I am producing needs to have certain tags present even if they are blank, but some need to be removed if they are blank.



To go even further, if what I had is ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz>"zzzz"</buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds> <!-- Fixed by edit -->
</sounds>
</farm>


In this example,<sounds>, <moo>, <meow>, and <buzz> would need to stay since <buzz> has a value, but <birds> and its children would need to be removed.



This seems so complicated to me, I am not sure what the simplest way to do this would be.



Thank you so much for your guidance, as I feel dizzy from going in so many circles!










share|improve this question
















I am new to using xsl and I am not sure how to remove specific parent nodes and all their children, if all are empty. I think the answer shown in this link is what I need, but I am not sure how to apply this to a specific node instead of the whole stylesheet.



Using what is in that question, I have expanded it ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz></buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds>
</sounds>
</farm>


How can I just eliminate <sounds> and all of its children (if they are all empty) while leaving empty nodes like foo, bar, and baz. The requirements for the xml I am producing needs to have certain tags present even if they are blank, but some need to be removed if they are blank.



To go even further, if what I had is ...



<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz>"zzzz"</buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds> <!-- Fixed by edit -->
</sounds>
</farm>


In this example,<sounds>, <moo>, <meow>, and <buzz> would need to stay since <buzz> has a value, but <birds> and its children would need to be removed.



This seems so complicated to me, I am not sure what the simplest way to do this would be.



Thank you so much for your guidance, as I feel dizzy from going in so many circles!







xml xslt






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 18:27









zx485

13.7k122946




13.7k122946










asked Nov 21 '18 at 18:00









ShysoksShysoks

11




11













  • I don't understand you question. Is there a list of elements you want to keep even if they are empty? If so, how would it look in the given examples? -- BTW, cluck is not really empty - so I guess you want to consider whitespace-only as empty?

    – michael.hor257k
    Nov 21 '18 at 18:06











  • Also tell us which version of XSLT your processor supports.

    – michael.hor257k
    Nov 21 '18 at 18:07



















  • I don't understand you question. Is there a list of elements you want to keep even if they are empty? If so, how would it look in the given examples? -- BTW, cluck is not really empty - so I guess you want to consider whitespace-only as empty?

    – michael.hor257k
    Nov 21 '18 at 18:06











  • Also tell us which version of XSLT your processor supports.

    – michael.hor257k
    Nov 21 '18 at 18:07

















I don't understand you question. Is there a list of elements you want to keep even if they are empty? If so, how would it look in the given examples? -- BTW, cluck is not really empty - so I guess you want to consider whitespace-only as empty?

– michael.hor257k
Nov 21 '18 at 18:06





I don't understand you question. Is there a list of elements you want to keep even if they are empty? If so, how would it look in the given examples? -- BTW, cluck is not really empty - so I guess you want to consider whitespace-only as empty?

– michael.hor257k
Nov 21 '18 at 18:06













Also tell us which version of XSLT your processor supports.

– michael.hor257k
Nov 21 '18 at 18:07





Also tell us which version of XSLT your processor supports.

– michael.hor257k
Nov 21 '18 at 18:07












2 Answers
2






active

oldest

votes


















1














If your processor doesn't support XSLT 3.0, here's an XSLT 1.0 option...



<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="*[ancestor-or-self::sounds][not(string())]"/>

</xsl:stylesheet>


Fiddle for example #1: http://xsltfiddle.liberty-development.net/jyH9rNp



Fiddle for example #2: http://xsltfiddle.liberty-development.net/jyH9rNp/1






share|improve this answer
























  • Yes, we are using version 1. I will try this and let you know. Thanks!

    – Shysoks
    Nov 21 '18 at 18:40











  • @Shysoks - Were you able to resolve your issue or are you still having problems?

    – Daniel Haley
    Nov 28 '18 at 21:18



















0














Assuming XSLT 3 (supported for the Java platform with Saxon 9.8 and 9.9 and for the .NET platform with Saxon 9.8, also by Altova 2017/2018/2019) you could use xsl:where-populated together with xsl:next-match for sounds and any descendant elements and the identity transformation for the rest; additionally you would need to strip white space, otherwise <cluck> </cluck> would not be removed:



<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

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

<xsl:template match="sounds | sounds//*">
<xsl:where-populated>
<xsl:next-match/>
</xsl:where-populated>
</xsl:template>

</xsl:stylesheet>


https://xsltfiddle.liberty-development.net/gWmuiKn/0 has your first input and https://xsltfiddle.liberty-development.net/gWmuiKn/1 your second.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418048%2frecursively-remove-nodes-when-children-are-empty-in-xslt%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    If your processor doesn't support XSLT 3.0, here's an XSLT 1.0 option...



    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="*[ancestor-or-self::sounds][not(string())]"/>

    </xsl:stylesheet>


    Fiddle for example #1: http://xsltfiddle.liberty-development.net/jyH9rNp



    Fiddle for example #2: http://xsltfiddle.liberty-development.net/jyH9rNp/1






    share|improve this answer
























    • Yes, we are using version 1. I will try this and let you know. Thanks!

      – Shysoks
      Nov 21 '18 at 18:40











    • @Shysoks - Were you able to resolve your issue or are you still having problems?

      – Daniel Haley
      Nov 28 '18 at 21:18
















    1














    If your processor doesn't support XSLT 3.0, here's an XSLT 1.0 option...



    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="*[ancestor-or-self::sounds][not(string())]"/>

    </xsl:stylesheet>


    Fiddle for example #1: http://xsltfiddle.liberty-development.net/jyH9rNp



    Fiddle for example #2: http://xsltfiddle.liberty-development.net/jyH9rNp/1






    share|improve this answer
























    • Yes, we are using version 1. I will try this and let you know. Thanks!

      – Shysoks
      Nov 21 '18 at 18:40











    • @Shysoks - Were you able to resolve your issue or are you still having problems?

      – Daniel Haley
      Nov 28 '18 at 21:18














    1












    1








    1







    If your processor doesn't support XSLT 3.0, here's an XSLT 1.0 option...



    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="*[ancestor-or-self::sounds][not(string())]"/>

    </xsl:stylesheet>


    Fiddle for example #1: http://xsltfiddle.liberty-development.net/jyH9rNp



    Fiddle for example #2: http://xsltfiddle.liberty-development.net/jyH9rNp/1






    share|improve this answer













    If your processor doesn't support XSLT 3.0, here's an XSLT 1.0 option...



    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="*[ancestor-or-self::sounds][not(string())]"/>

    </xsl:stylesheet>


    Fiddle for example #1: http://xsltfiddle.liberty-development.net/jyH9rNp



    Fiddle for example #2: http://xsltfiddle.liberty-development.net/jyH9rNp/1







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 21 '18 at 18:36









    Daniel HaleyDaniel Haley

    38.6k45280




    38.6k45280













    • Yes, we are using version 1. I will try this and let you know. Thanks!

      – Shysoks
      Nov 21 '18 at 18:40











    • @Shysoks - Were you able to resolve your issue or are you still having problems?

      – Daniel Haley
      Nov 28 '18 at 21:18



















    • Yes, we are using version 1. I will try this and let you know. Thanks!

      – Shysoks
      Nov 21 '18 at 18:40











    • @Shysoks - Were you able to resolve your issue or are you still having problems?

      – Daniel Haley
      Nov 28 '18 at 21:18

















    Yes, we are using version 1. I will try this and let you know. Thanks!

    – Shysoks
    Nov 21 '18 at 18:40





    Yes, we are using version 1. I will try this and let you know. Thanks!

    – Shysoks
    Nov 21 '18 at 18:40













    @Shysoks - Were you able to resolve your issue or are you still having problems?

    – Daniel Haley
    Nov 28 '18 at 21:18





    @Shysoks - Were you able to resolve your issue or are you still having problems?

    – Daniel Haley
    Nov 28 '18 at 21:18













    0














    Assuming XSLT 3 (supported for the Java platform with Saxon 9.8 and 9.9 and for the .NET platform with Saxon 9.8, also by Altova 2017/2018/2019) you could use xsl:where-populated together with xsl:next-match for sounds and any descendant elements and the identity transformation for the rest; additionally you would need to strip white space, otherwise <cluck> </cluck> would not be removed:



    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

    <xsl:mode on-no-match="shallow-copy"/>

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

    <xsl:template match="sounds | sounds//*">
    <xsl:where-populated>
    <xsl:next-match/>
    </xsl:where-populated>
    </xsl:template>

    </xsl:stylesheet>


    https://xsltfiddle.liberty-development.net/gWmuiKn/0 has your first input and https://xsltfiddle.liberty-development.net/gWmuiKn/1 your second.






    share|improve this answer




























      0














      Assuming XSLT 3 (supported for the Java platform with Saxon 9.8 and 9.9 and for the .NET platform with Saxon 9.8, also by Altova 2017/2018/2019) you could use xsl:where-populated together with xsl:next-match for sounds and any descendant elements and the identity transformation for the rest; additionally you would need to strip white space, otherwise <cluck> </cluck> would not be removed:



      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="#all"
      version="3.0">

      <xsl:mode on-no-match="shallow-copy"/>

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

      <xsl:template match="sounds | sounds//*">
      <xsl:where-populated>
      <xsl:next-match/>
      </xsl:where-populated>
      </xsl:template>

      </xsl:stylesheet>


      https://xsltfiddle.liberty-development.net/gWmuiKn/0 has your first input and https://xsltfiddle.liberty-development.net/gWmuiKn/1 your second.






      share|improve this answer


























        0












        0








        0







        Assuming XSLT 3 (supported for the Java platform with Saxon 9.8 and 9.9 and for the .NET platform with Saxon 9.8, also by Altova 2017/2018/2019) you could use xsl:where-populated together with xsl:next-match for sounds and any descendant elements and the identity transformation for the rest; additionally you would need to strip white space, otherwise <cluck> </cluck> would not be removed:



        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="#all"
        version="3.0">

        <xsl:mode on-no-match="shallow-copy"/>

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

        <xsl:template match="sounds | sounds//*">
        <xsl:where-populated>
        <xsl:next-match/>
        </xsl:where-populated>
        </xsl:template>

        </xsl:stylesheet>


        https://xsltfiddle.liberty-development.net/gWmuiKn/0 has your first input and https://xsltfiddle.liberty-development.net/gWmuiKn/1 your second.






        share|improve this answer













        Assuming XSLT 3 (supported for the Java platform with Saxon 9.8 and 9.9 and for the .NET platform with Saxon 9.8, also by Altova 2017/2018/2019) you could use xsl:where-populated together with xsl:next-match for sounds and any descendant elements and the identity transformation for the rest; additionally you would need to strip white space, otherwise <cluck> </cluck> would not be removed:



        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="#all"
        version="3.0">

        <xsl:mode on-no-match="shallow-copy"/>

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

        <xsl:template match="sounds | sounds//*">
        <xsl:where-populated>
        <xsl:next-match/>
        </xsl:where-populated>
        </xsl:template>

        </xsl:stylesheet>


        https://xsltfiddle.liberty-development.net/gWmuiKn/0 has your first input and https://xsltfiddle.liberty-development.net/gWmuiKn/1 your second.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 21 '18 at 18:16









        Martin HonnenMartin Honnen

        111k65976




        111k65976






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418048%2frecursively-remove-nodes-when-children-are-empty-in-xslt%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Ottavio Pratesi

            Tricia Helfer

            15 giugno