XSLT: Remove Empty Nodes ~AND~ Nodes with Literal Value “Null”












1















All,



I have been using the extremely basic stylesheet at the very bottom of this post to remove empty element nodes from XML records. The XSLT does the job adequately, but the XML records actually include literal "null" values in some elements that the stylesheet doesn't remove. Example:



<marc:datafield tag="400" ind1="1" ind2=" ">
<marc:subfield code="a">null</marc:subfield>
<marc:subfield code="q">null</marc:subfield>
<marc:subfield code="d"></marc:subfield>
</marc:datafield>


I've been removing these "nulls" manually with a find and replace prior to running the XSLT, a procedure that works well enough--but it would be more sensible to have the XSLT itself remove these values as well as any empty nodes. In other words, I'd like to strip out nodes that contain "null"



<marc:subfield code="q">null</marc:subfield>


AND nodes like



<marc:subfield code="q"></marc:subfield>


so that the entire block of nodes represented in the top example in this message disappears entirely.



The XSLT immediately below succeeds in removing nodes with the literal "null" value, but it leaves the empty nodes in place. I need the XSLT to do both things simultaneously: remove literal "null" values and the nodes that contain them as well as the empty nodes. I've tried doing a "choose-otherwise" condition but it doesn't work.



<xsl:strip-space elements="*"/>
<xsl:template match="*[not(node())]"/>
<xsl:template match="node()|@*">
<xsl:if test="(. != '') and (. != 'null')">
<xsl:copy>
<xsl:apply-templates select="node()[normalize-space()]|@*"/>
</xsl:copy>
</xsl:if>
</xsl:template>




Any assistance you might be able to offer would be hugely, immensely appreciated.



Regards, and many thanks--



Sed V.



ORIGINAL XSLT:



<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*[not(node())]"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()[normalize-space()]|@*"/>
</xsl:copy>
</xsl:template>











share|improve this question





























    1















    All,



    I have been using the extremely basic stylesheet at the very bottom of this post to remove empty element nodes from XML records. The XSLT does the job adequately, but the XML records actually include literal "null" values in some elements that the stylesheet doesn't remove. Example:



    <marc:datafield tag="400" ind1="1" ind2=" ">
    <marc:subfield code="a">null</marc:subfield>
    <marc:subfield code="q">null</marc:subfield>
    <marc:subfield code="d"></marc:subfield>
    </marc:datafield>


    I've been removing these "nulls" manually with a find and replace prior to running the XSLT, a procedure that works well enough--but it would be more sensible to have the XSLT itself remove these values as well as any empty nodes. In other words, I'd like to strip out nodes that contain "null"



    <marc:subfield code="q">null</marc:subfield>


    AND nodes like



    <marc:subfield code="q"></marc:subfield>


    so that the entire block of nodes represented in the top example in this message disappears entirely.



    The XSLT immediately below succeeds in removing nodes with the literal "null" value, but it leaves the empty nodes in place. I need the XSLT to do both things simultaneously: remove literal "null" values and the nodes that contain them as well as the empty nodes. I've tried doing a "choose-otherwise" condition but it doesn't work.



    <xsl:strip-space elements="*"/>
    <xsl:template match="*[not(node())]"/>
    <xsl:template match="node()|@*">
    <xsl:if test="(. != '') and (. != 'null')">
    <xsl:copy>
    <xsl:apply-templates select="node()[normalize-space()]|@*"/>
    </xsl:copy>
    </xsl:if>
    </xsl:template>




    Any assistance you might be able to offer would be hugely, immensely appreciated.



    Regards, and many thanks--



    Sed V.



    ORIGINAL XSLT:



    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="*[not(node())]"/>
    <xsl:template match="node()|@*">
    <xsl:copy>
    <xsl:apply-templates select="node()[normalize-space()]|@*"/>
    </xsl:copy>
    </xsl:template>











    share|improve this question



























      1












      1








      1








      All,



      I have been using the extremely basic stylesheet at the very bottom of this post to remove empty element nodes from XML records. The XSLT does the job adequately, but the XML records actually include literal "null" values in some elements that the stylesheet doesn't remove. Example:



      <marc:datafield tag="400" ind1="1" ind2=" ">
      <marc:subfield code="a">null</marc:subfield>
      <marc:subfield code="q">null</marc:subfield>
      <marc:subfield code="d"></marc:subfield>
      </marc:datafield>


      I've been removing these "nulls" manually with a find and replace prior to running the XSLT, a procedure that works well enough--but it would be more sensible to have the XSLT itself remove these values as well as any empty nodes. In other words, I'd like to strip out nodes that contain "null"



      <marc:subfield code="q">null</marc:subfield>


      AND nodes like



      <marc:subfield code="q"></marc:subfield>


      so that the entire block of nodes represented in the top example in this message disappears entirely.



      The XSLT immediately below succeeds in removing nodes with the literal "null" value, but it leaves the empty nodes in place. I need the XSLT to do both things simultaneously: remove literal "null" values and the nodes that contain them as well as the empty nodes. I've tried doing a "choose-otherwise" condition but it doesn't work.



      <xsl:strip-space elements="*"/>
      <xsl:template match="*[not(node())]"/>
      <xsl:template match="node()|@*">
      <xsl:if test="(. != '') and (. != 'null')">
      <xsl:copy>
      <xsl:apply-templates select="node()[normalize-space()]|@*"/>
      </xsl:copy>
      </xsl:if>
      </xsl:template>




      Any assistance you might be able to offer would be hugely, immensely appreciated.



      Regards, and many thanks--



      Sed V.



      ORIGINAL XSLT:



      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/>
      <xsl:strip-space elements="*"/>
      <xsl:template match="*[not(node())]"/>
      <xsl:template match="node()|@*">
      <xsl:copy>
      <xsl:apply-templates select="node()[normalize-space()]|@*"/>
      </xsl:copy>
      </xsl:template>











      share|improve this question
















      All,



      I have been using the extremely basic stylesheet at the very bottom of this post to remove empty element nodes from XML records. The XSLT does the job adequately, but the XML records actually include literal "null" values in some elements that the stylesheet doesn't remove. Example:



      <marc:datafield tag="400" ind1="1" ind2=" ">
      <marc:subfield code="a">null</marc:subfield>
      <marc:subfield code="q">null</marc:subfield>
      <marc:subfield code="d"></marc:subfield>
      </marc:datafield>


      I've been removing these "nulls" manually with a find and replace prior to running the XSLT, a procedure that works well enough--but it would be more sensible to have the XSLT itself remove these values as well as any empty nodes. In other words, I'd like to strip out nodes that contain "null"



      <marc:subfield code="q">null</marc:subfield>


      AND nodes like



      <marc:subfield code="q"></marc:subfield>


      so that the entire block of nodes represented in the top example in this message disappears entirely.



      The XSLT immediately below succeeds in removing nodes with the literal "null" value, but it leaves the empty nodes in place. I need the XSLT to do both things simultaneously: remove literal "null" values and the nodes that contain them as well as the empty nodes. I've tried doing a "choose-otherwise" condition but it doesn't work.



      <xsl:strip-space elements="*"/>
      <xsl:template match="*[not(node())]"/>
      <xsl:template match="node()|@*">
      <xsl:if test="(. != '') and (. != 'null')">
      <xsl:copy>
      <xsl:apply-templates select="node()[normalize-space()]|@*"/>
      </xsl:copy>
      </xsl:if>
      </xsl:template>




      Any assistance you might be able to offer would be hugely, immensely appreciated.



      Regards, and many thanks--



      Sed V.



      ORIGINAL XSLT:



      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/>
      <xsl:strip-space elements="*"/>
      <xsl:template match="*[not(node())]"/>
      <xsl:template match="node()|@*">
      <xsl:copy>
      <xsl:apply-templates select="node()[normalize-space()]|@*"/>
      </xsl:copy>
      </xsl:template>








      xslt






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 '18 at 18:49









      pushkin

      4,050112752




      4,050112752










      asked Nov 20 '18 at 18:43









      Sediziose_VociSediziose_Voci

      61




      61
























          1 Answer
          1






          active

          oldest

          votes


















          0














          You're almost there. Your template



          <xsl:template match="*[not(node())]"/>


          filters empty elements - just add or text() = 'null' to the predicate to filter elements that wrap literal null strings.



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

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

          <!-- Filter empty elements or elements that contain the text 'null' -->
          <xsl:template match="*[not(node()) or text() = 'null']"/>
          </xsl:stylesheet>





          share|improve this answer
























          • Thank you, thank you. This is extremely helpful. The formula below is what ended up doing what I needed. It includes the crucial, indispensable piece you supplied.

            – Sediziose_Voci
            Nov 20 '18 at 23:09













          • <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/> <xsl:strip-space elements=""/> <xsl:template match="*[not(node())]"/> <xsl:template match="node()|@"> <xsl:copy> <xsl:apply-templates select="node()[normalize-space()]|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node()) or text() = 'null']"/> </xsl:stylesheet>

            – Sediziose_Voci
            Nov 20 '18 at 23:12











          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%2f53399519%2fxslt-remove-empty-nodes-and-nodes-with-literal-value-null%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          You're almost there. Your template



          <xsl:template match="*[not(node())]"/>


          filters empty elements - just add or text() = 'null' to the predicate to filter elements that wrap literal null strings.



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

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

          <!-- Filter empty elements or elements that contain the text 'null' -->
          <xsl:template match="*[not(node()) or text() = 'null']"/>
          </xsl:stylesheet>





          share|improve this answer
























          • Thank you, thank you. This is extremely helpful. The formula below is what ended up doing what I needed. It includes the crucial, indispensable piece you supplied.

            – Sediziose_Voci
            Nov 20 '18 at 23:09













          • <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/> <xsl:strip-space elements=""/> <xsl:template match="*[not(node())]"/> <xsl:template match="node()|@"> <xsl:copy> <xsl:apply-templates select="node()[normalize-space()]|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node()) or text() = 'null']"/> </xsl:stylesheet>

            – Sediziose_Voci
            Nov 20 '18 at 23:12
















          0














          You're almost there. Your template



          <xsl:template match="*[not(node())]"/>


          filters empty elements - just add or text() = 'null' to the predicate to filter elements that wrap literal null strings.



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

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

          <!-- Filter empty elements or elements that contain the text 'null' -->
          <xsl:template match="*[not(node()) or text() = 'null']"/>
          </xsl:stylesheet>





          share|improve this answer
























          • Thank you, thank you. This is extremely helpful. The formula below is what ended up doing what I needed. It includes the crucial, indispensable piece you supplied.

            – Sediziose_Voci
            Nov 20 '18 at 23:09













          • <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/> <xsl:strip-space elements=""/> <xsl:template match="*[not(node())]"/> <xsl:template match="node()|@"> <xsl:copy> <xsl:apply-templates select="node()[normalize-space()]|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node()) or text() = 'null']"/> </xsl:stylesheet>

            – Sediziose_Voci
            Nov 20 '18 at 23:12














          0












          0








          0







          You're almost there. Your template



          <xsl:template match="*[not(node())]"/>


          filters empty elements - just add or text() = 'null' to the predicate to filter elements that wrap literal null strings.



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

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

          <!-- Filter empty elements or elements that contain the text 'null' -->
          <xsl:template match="*[not(node()) or text() = 'null']"/>
          </xsl:stylesheet>





          share|improve this answer













          You're almost there. Your template



          <xsl:template match="*[not(node())]"/>


          filters empty elements - just add or text() = 'null' to the predicate to filter elements that wrap literal null strings.



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

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

          <!-- Filter empty elements or elements that contain the text 'null' -->
          <xsl:template match="*[not(node()) or text() = 'null']"/>
          </xsl:stylesheet>






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 20 '18 at 19:19









          teppicteppic

          5,30411826




          5,30411826













          • Thank you, thank you. This is extremely helpful. The formula below is what ended up doing what I needed. It includes the crucial, indispensable piece you supplied.

            – Sediziose_Voci
            Nov 20 '18 at 23:09













          • <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/> <xsl:strip-space elements=""/> <xsl:template match="*[not(node())]"/> <xsl:template match="node()|@"> <xsl:copy> <xsl:apply-templates select="node()[normalize-space()]|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node()) or text() = 'null']"/> </xsl:stylesheet>

            – Sediziose_Voci
            Nov 20 '18 at 23:12



















          • Thank you, thank you. This is extremely helpful. The formula below is what ended up doing what I needed. It includes the crucial, indispensable piece you supplied.

            – Sediziose_Voci
            Nov 20 '18 at 23:09













          • <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/> <xsl:strip-space elements=""/> <xsl:template match="*[not(node())]"/> <xsl:template match="node()|@"> <xsl:copy> <xsl:apply-templates select="node()[normalize-space()]|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node()) or text() = 'null']"/> </xsl:stylesheet>

            – Sediziose_Voci
            Nov 20 '18 at 23:12

















          Thank you, thank you. This is extremely helpful. The formula below is what ended up doing what I needed. It includes the crucial, indispensable piece you supplied.

          – Sediziose_Voci
          Nov 20 '18 at 23:09







          Thank you, thank you. This is extremely helpful. The formula below is what ended up doing what I needed. It includes the crucial, indispensable piece you supplied.

          – Sediziose_Voci
          Nov 20 '18 at 23:09















          <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/> <xsl:strip-space elements=""/> <xsl:template match="*[not(node())]"/> <xsl:template match="node()|@"> <xsl:copy> <xsl:apply-templates select="node()[normalize-space()]|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node()) or text() = 'null']"/> </xsl:stylesheet>

          – Sediziose_Voci
          Nov 20 '18 at 23:12





          <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/> <xsl:strip-space elements=""/> <xsl:template match="*[not(node())]"/> <xsl:template match="node()|@"> <xsl:copy> <xsl:apply-templates select="node()[normalize-space()]|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node()) or text() = 'null']"/> </xsl:stylesheet>

          – Sediziose_Voci
          Nov 20 '18 at 23:12




















          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%2f53399519%2fxslt-remove-empty-nodes-and-nodes-with-literal-value-null%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

          Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

          ComboBox Display Member on multiple fields

          Is it possible to collect Nectar points via Trainline?