Recursively remove nodes when children are empty in XSLT
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
add a comment |
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
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,cluckis 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
add a comment |
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
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
xml xslt
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,cluckis 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
add a comment |
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,cluckis 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
add a comment |
2 Answers
2
active
oldest
votes
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
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
add a comment |
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Nov 21 '18 at 18:16
Martin HonnenMartin Honnen
111k65976
111k65976
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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,
cluckis 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