XSLT: How to select siblings with a condition










0















I have the following XML:



 <?xml version="1.0" encoding="UTF-8"?>
<thesaurus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<term id="01">
<name>
<value>green</value>
</name>
<info>
<ref rid="12" obj-type="Building" />
</info>
<info>
<ref rid="13" obj-type="House" />
</info>
<info>
<ref rid="14" obj-type="Apartment"/>
</info>
</term>
<term id="02">
<name>
<value>blue</value>
</name>
<info>
<ref rid="24" obj-type="Unknown"/>
</info>
<info>
<ref rid="26" obj-type="Unknown"/>
</info>
<info>
<ref rid="29" obj-type="Unknown"/>
</info>
</term>
<term id="03">
<name>
<value>yellow</value>
</name>
</term>
<term id="04">
<name>
<value>red</value>
</name>
<info>
<ref rid="40" obj-type="Hotel"/>
</info>
<info>
<ref rid="41" obj-type="Building"/>
</info>
<info>
<ref rid="43" obj-type="House"/>
</info>
</term>
<term id="05">
<name>
<value>purple</value>
</name>
</term>
<term id="06">
<name>
<value>magenta</value>
</name>

<info>
<ref rid="60" obj-type="Building"/>
</info>
<info>
<ref rid="62" obj-type="Unknown"/>
</info>
<info>
<ref rid="64" obj-type="House"/>
</info>
</term>
</thesaurus>



What I want is this:



1) Select all <term> tags that without an <info> tag. This is
already accomplished with the first apply-templates:
select="term[not(info)]" in the XSLT below.



2) Select all <term> tags when its <ref> tag contains an
obj-type="Unknown" alone or multiple times, but don't select it if
it's surrounded by obj-types with values different than "Unknown"
(like Building or House).



*** Inside an <info> tag, when having obj-type siblings with other values,
it takes at least one value of 'Unknown' for the <term> tag to not
be selected.





If the XSLT works well, the tags selected will be:



02, 03, 05



where:




01 won't be selected because it contains <info> tags, and none of those tags has a obj-type='Unknown'



02 will be selected because there are three multiple values of 'Unknown', and
no other values different than 'Unknown'



03 will be selected because it does not contains <info> tags



04 won't be selected because it contains <info> tags with obj-type values different than 'Unknown'.



05 will be selected because there are no info tags.



06 won't be selected because although there is one value of 'Unknown',
all the other <ref> siblings have a value obj-type different than 'Unknown'.



*** REMEMBER: Inside an <info> tag, when having obj-type siblings with other values, it takes at least one value of
'Unknown' for the <term> tag to not be selected.





I'm using the XSLT below. With the first apply-templates I can select all the tags without an <info> tag.



With the second apply-templates I can select all the <term> tags that contain a <ref> tag with an obj-type="Unknown", but I don't know how to tell the XSLT that if there are obj-types with a different value, don't select the corresponding <term> tag.



I tried to use a for-each and a conditional, to iterate through all the <ref> children and check whether one of the siblings had a different value than 'Unknown' to not select its <term> parent, but to no avail.



<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 
<xsl:output method="text"/>

<xsl:template match="/thesaurus">

<xsl:apply-templates select="term[not(info)]"/>

<xsl:apply-templates select="term[info/ref[@obj-type='Unknown']]"/>

</xsl:template>

<xsl:template match="term">

<xsl:value-of select="@id"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="name"/>
<xsl:text>,</xsl:text>
<xsl:text>
</xsl:text>

</xsl:template>

<xsl:template match="term[info/ref]">

<xsl:value-of select="@id"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="name"/>
<xsl:text>,</xsl:text>
<xsl:text>
</xsl:text>

</xsl:template>

</xsl:stylesheet>


I hope it's clear.










share|improve this question


























    0















    I have the following XML:



     <?xml version="1.0" encoding="UTF-8"?>
    <thesaurus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <term id="01">
    <name>
    <value>green</value>
    </name>
    <info>
    <ref rid="12" obj-type="Building" />
    </info>
    <info>
    <ref rid="13" obj-type="House" />
    </info>
    <info>
    <ref rid="14" obj-type="Apartment"/>
    </info>
    </term>
    <term id="02">
    <name>
    <value>blue</value>
    </name>
    <info>
    <ref rid="24" obj-type="Unknown"/>
    </info>
    <info>
    <ref rid="26" obj-type="Unknown"/>
    </info>
    <info>
    <ref rid="29" obj-type="Unknown"/>
    </info>
    </term>
    <term id="03">
    <name>
    <value>yellow</value>
    </name>
    </term>
    <term id="04">
    <name>
    <value>red</value>
    </name>
    <info>
    <ref rid="40" obj-type="Hotel"/>
    </info>
    <info>
    <ref rid="41" obj-type="Building"/>
    </info>
    <info>
    <ref rid="43" obj-type="House"/>
    </info>
    </term>
    <term id="05">
    <name>
    <value>purple</value>
    </name>
    </term>
    <term id="06">
    <name>
    <value>magenta</value>
    </name>

    <info>
    <ref rid="60" obj-type="Building"/>
    </info>
    <info>
    <ref rid="62" obj-type="Unknown"/>
    </info>
    <info>
    <ref rid="64" obj-type="House"/>
    </info>
    </term>
    </thesaurus>



    What I want is this:



    1) Select all <term> tags that without an <info> tag. This is
    already accomplished with the first apply-templates:
    select="term[not(info)]" in the XSLT below.



    2) Select all <term> tags when its <ref> tag contains an
    obj-type="Unknown" alone or multiple times, but don't select it if
    it's surrounded by obj-types with values different than "Unknown"
    (like Building or House).



    *** Inside an <info> tag, when having obj-type siblings with other values,
    it takes at least one value of 'Unknown' for the <term> tag to not
    be selected.





    If the XSLT works well, the tags selected will be:



    02, 03, 05



    where:




    01 won't be selected because it contains <info> tags, and none of those tags has a obj-type='Unknown'



    02 will be selected because there are three multiple values of 'Unknown', and
    no other values different than 'Unknown'



    03 will be selected because it does not contains <info> tags



    04 won't be selected because it contains <info> tags with obj-type values different than 'Unknown'.



    05 will be selected because there are no info tags.



    06 won't be selected because although there is one value of 'Unknown',
    all the other <ref> siblings have a value obj-type different than 'Unknown'.



    *** REMEMBER: Inside an <info> tag, when having obj-type siblings with other values, it takes at least one value of
    'Unknown' for the <term> tag to not be selected.





    I'm using the XSLT below. With the first apply-templates I can select all the tags without an <info> tag.



    With the second apply-templates I can select all the <term> tags that contain a <ref> tag with an obj-type="Unknown", but I don't know how to tell the XSLT that if there are obj-types with a different value, don't select the corresponding <term> tag.



    I tried to use a for-each and a conditional, to iterate through all the <ref> children and check whether one of the siblings had a different value than 'Unknown' to not select its <term> parent, but to no avail.



    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 
    <xsl:output method="text"/>

    <xsl:template match="/thesaurus">

    <xsl:apply-templates select="term[not(info)]"/>

    <xsl:apply-templates select="term[info/ref[@obj-type='Unknown']]"/>

    </xsl:template>

    <xsl:template match="term">

    <xsl:value-of select="@id"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="name"/>
    <xsl:text>,</xsl:text>
    <xsl:text>
    </xsl:text>

    </xsl:template>

    <xsl:template match="term[info/ref]">

    <xsl:value-of select="@id"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="name"/>
    <xsl:text>,</xsl:text>
    <xsl:text>
    </xsl:text>

    </xsl:template>

    </xsl:stylesheet>


    I hope it's clear.










    share|improve this question
























      0












      0








      0








      I have the following XML:



       <?xml version="1.0" encoding="UTF-8"?>
      <thesaurus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

      <term id="01">
      <name>
      <value>green</value>
      </name>
      <info>
      <ref rid="12" obj-type="Building" />
      </info>
      <info>
      <ref rid="13" obj-type="House" />
      </info>
      <info>
      <ref rid="14" obj-type="Apartment"/>
      </info>
      </term>
      <term id="02">
      <name>
      <value>blue</value>
      </name>
      <info>
      <ref rid="24" obj-type="Unknown"/>
      </info>
      <info>
      <ref rid="26" obj-type="Unknown"/>
      </info>
      <info>
      <ref rid="29" obj-type="Unknown"/>
      </info>
      </term>
      <term id="03">
      <name>
      <value>yellow</value>
      </name>
      </term>
      <term id="04">
      <name>
      <value>red</value>
      </name>
      <info>
      <ref rid="40" obj-type="Hotel"/>
      </info>
      <info>
      <ref rid="41" obj-type="Building"/>
      </info>
      <info>
      <ref rid="43" obj-type="House"/>
      </info>
      </term>
      <term id="05">
      <name>
      <value>purple</value>
      </name>
      </term>
      <term id="06">
      <name>
      <value>magenta</value>
      </name>

      <info>
      <ref rid="60" obj-type="Building"/>
      </info>
      <info>
      <ref rid="62" obj-type="Unknown"/>
      </info>
      <info>
      <ref rid="64" obj-type="House"/>
      </info>
      </term>
      </thesaurus>



      What I want is this:



      1) Select all <term> tags that without an <info> tag. This is
      already accomplished with the first apply-templates:
      select="term[not(info)]" in the XSLT below.



      2) Select all <term> tags when its <ref> tag contains an
      obj-type="Unknown" alone or multiple times, but don't select it if
      it's surrounded by obj-types with values different than "Unknown"
      (like Building or House).



      *** Inside an <info> tag, when having obj-type siblings with other values,
      it takes at least one value of 'Unknown' for the <term> tag to not
      be selected.





      If the XSLT works well, the tags selected will be:



      02, 03, 05



      where:




      01 won't be selected because it contains <info> tags, and none of those tags has a obj-type='Unknown'



      02 will be selected because there are three multiple values of 'Unknown', and
      no other values different than 'Unknown'



      03 will be selected because it does not contains <info> tags



      04 won't be selected because it contains <info> tags with obj-type values different than 'Unknown'.



      05 will be selected because there are no info tags.



      06 won't be selected because although there is one value of 'Unknown',
      all the other <ref> siblings have a value obj-type different than 'Unknown'.



      *** REMEMBER: Inside an <info> tag, when having obj-type siblings with other values, it takes at least one value of
      'Unknown' for the <term> tag to not be selected.





      I'm using the XSLT below. With the first apply-templates I can select all the tags without an <info> tag.



      With the second apply-templates I can select all the <term> tags that contain a <ref> tag with an obj-type="Unknown", but I don't know how to tell the XSLT that if there are obj-types with a different value, don't select the corresponding <term> tag.



      I tried to use a for-each and a conditional, to iterate through all the <ref> children and check whether one of the siblings had a different value than 'Unknown' to not select its <term> parent, but to no avail.



      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 
      <xsl:output method="text"/>

      <xsl:template match="/thesaurus">

      <xsl:apply-templates select="term[not(info)]"/>

      <xsl:apply-templates select="term[info/ref[@obj-type='Unknown']]"/>

      </xsl:template>

      <xsl:template match="term">

      <xsl:value-of select="@id"/>
      <xsl:text>,</xsl:text>
      <xsl:value-of select="name"/>
      <xsl:text>,</xsl:text>
      <xsl:text>
      </xsl:text>

      </xsl:template>

      <xsl:template match="term[info/ref]">

      <xsl:value-of select="@id"/>
      <xsl:text>,</xsl:text>
      <xsl:value-of select="name"/>
      <xsl:text>,</xsl:text>
      <xsl:text>
      </xsl:text>

      </xsl:template>

      </xsl:stylesheet>


      I hope it's clear.










      share|improve this question














      I have the following XML:



       <?xml version="1.0" encoding="UTF-8"?>
      <thesaurus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

      <term id="01">
      <name>
      <value>green</value>
      </name>
      <info>
      <ref rid="12" obj-type="Building" />
      </info>
      <info>
      <ref rid="13" obj-type="House" />
      </info>
      <info>
      <ref rid="14" obj-type="Apartment"/>
      </info>
      </term>
      <term id="02">
      <name>
      <value>blue</value>
      </name>
      <info>
      <ref rid="24" obj-type="Unknown"/>
      </info>
      <info>
      <ref rid="26" obj-type="Unknown"/>
      </info>
      <info>
      <ref rid="29" obj-type="Unknown"/>
      </info>
      </term>
      <term id="03">
      <name>
      <value>yellow</value>
      </name>
      </term>
      <term id="04">
      <name>
      <value>red</value>
      </name>
      <info>
      <ref rid="40" obj-type="Hotel"/>
      </info>
      <info>
      <ref rid="41" obj-type="Building"/>
      </info>
      <info>
      <ref rid="43" obj-type="House"/>
      </info>
      </term>
      <term id="05">
      <name>
      <value>purple</value>
      </name>
      </term>
      <term id="06">
      <name>
      <value>magenta</value>
      </name>

      <info>
      <ref rid="60" obj-type="Building"/>
      </info>
      <info>
      <ref rid="62" obj-type="Unknown"/>
      </info>
      <info>
      <ref rid="64" obj-type="House"/>
      </info>
      </term>
      </thesaurus>



      What I want is this:



      1) Select all <term> tags that without an <info> tag. This is
      already accomplished with the first apply-templates:
      select="term[not(info)]" in the XSLT below.



      2) Select all <term> tags when its <ref> tag contains an
      obj-type="Unknown" alone or multiple times, but don't select it if
      it's surrounded by obj-types with values different than "Unknown"
      (like Building or House).



      *** Inside an <info> tag, when having obj-type siblings with other values,
      it takes at least one value of 'Unknown' for the <term> tag to not
      be selected.





      If the XSLT works well, the tags selected will be:



      02, 03, 05



      where:




      01 won't be selected because it contains <info> tags, and none of those tags has a obj-type='Unknown'



      02 will be selected because there are three multiple values of 'Unknown', and
      no other values different than 'Unknown'



      03 will be selected because it does not contains <info> tags



      04 won't be selected because it contains <info> tags with obj-type values different than 'Unknown'.



      05 will be selected because there are no info tags.



      06 won't be selected because although there is one value of 'Unknown',
      all the other <ref> siblings have a value obj-type different than 'Unknown'.



      *** REMEMBER: Inside an <info> tag, when having obj-type siblings with other values, it takes at least one value of
      'Unknown' for the <term> tag to not be selected.





      I'm using the XSLT below. With the first apply-templates I can select all the tags without an <info> tag.



      With the second apply-templates I can select all the <term> tags that contain a <ref> tag with an obj-type="Unknown", but I don't know how to tell the XSLT that if there are obj-types with a different value, don't select the corresponding <term> tag.



      I tried to use a for-each and a conditional, to iterate through all the <ref> children and check whether one of the siblings had a different value than 'Unknown' to not select its <term> parent, but to no avail.



      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 
      <xsl:output method="text"/>

      <xsl:template match="/thesaurus">

      <xsl:apply-templates select="term[not(info)]"/>

      <xsl:apply-templates select="term[info/ref[@obj-type='Unknown']]"/>

      </xsl:template>

      <xsl:template match="term">

      <xsl:value-of select="@id"/>
      <xsl:text>,</xsl:text>
      <xsl:value-of select="name"/>
      <xsl:text>,</xsl:text>
      <xsl:text>
      </xsl:text>

      </xsl:template>

      <xsl:template match="term[info/ref]">

      <xsl:value-of select="@id"/>
      <xsl:text>,</xsl:text>
      <xsl:value-of select="name"/>
      <xsl:text>,</xsl:text>
      <xsl:text>
      </xsl:text>

      </xsl:template>

      </xsl:stylesheet>


      I hope it's clear.







      xml xslt






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 15 '18 at 16:11









      mistervelamistervela

      4910




      4910






















          1 Answer
          1






          active

          oldest

          votes


















          1














          You could try selecting the terms who doesn't contain something other than Unknown



          <xsl:apply-templates select="term[not(info/ref[@obj-type!='Unknown'])]"/>


          Or adding an if statement in your term[info/ref] template



          <xsl:template match="term[info/ref]">
          <xsl:if test="not(info/ref[@obj-type!='Unknown'])">
          <xsl:value-of select="@id"/>
          <xsl:text>,</xsl:text>
          <xsl:value-of select="name"/>
          <xsl:text>,</xsl:text>
          <xsl:text>
          </xsl:text>
          </xsl:if>

          </xsl:template>





          share|improve this answer























          • It works. Thank you so much for taking your time to go through this code. I knew it was something that simple. I tried to use an IF but couldn't properly construct it in XSLT terms. Thanks again.

            – mistervela
            Nov 16 '18 at 10:11










          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%2f53323550%2fxslt-how-to-select-siblings-with-a-condition%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









          1














          You could try selecting the terms who doesn't contain something other than Unknown



          <xsl:apply-templates select="term[not(info/ref[@obj-type!='Unknown'])]"/>


          Or adding an if statement in your term[info/ref] template



          <xsl:template match="term[info/ref]">
          <xsl:if test="not(info/ref[@obj-type!='Unknown'])">
          <xsl:value-of select="@id"/>
          <xsl:text>,</xsl:text>
          <xsl:value-of select="name"/>
          <xsl:text>,</xsl:text>
          <xsl:text>
          </xsl:text>
          </xsl:if>

          </xsl:template>





          share|improve this answer























          • It works. Thank you so much for taking your time to go through this code. I knew it was something that simple. I tried to use an IF but couldn't properly construct it in XSLT terms. Thanks again.

            – mistervela
            Nov 16 '18 at 10:11















          1














          You could try selecting the terms who doesn't contain something other than Unknown



          <xsl:apply-templates select="term[not(info/ref[@obj-type!='Unknown'])]"/>


          Or adding an if statement in your term[info/ref] template



          <xsl:template match="term[info/ref]">
          <xsl:if test="not(info/ref[@obj-type!='Unknown'])">
          <xsl:value-of select="@id"/>
          <xsl:text>,</xsl:text>
          <xsl:value-of select="name"/>
          <xsl:text>,</xsl:text>
          <xsl:text>
          </xsl:text>
          </xsl:if>

          </xsl:template>





          share|improve this answer























          • It works. Thank you so much for taking your time to go through this code. I knew it was something that simple. I tried to use an IF but couldn't properly construct it in XSLT terms. Thanks again.

            – mistervela
            Nov 16 '18 at 10:11













          1












          1








          1







          You could try selecting the terms who doesn't contain something other than Unknown



          <xsl:apply-templates select="term[not(info/ref[@obj-type!='Unknown'])]"/>


          Or adding an if statement in your term[info/ref] template



          <xsl:template match="term[info/ref]">
          <xsl:if test="not(info/ref[@obj-type!='Unknown'])">
          <xsl:value-of select="@id"/>
          <xsl:text>,</xsl:text>
          <xsl:value-of select="name"/>
          <xsl:text>,</xsl:text>
          <xsl:text>
          </xsl:text>
          </xsl:if>

          </xsl:template>





          share|improve this answer













          You could try selecting the terms who doesn't contain something other than Unknown



          <xsl:apply-templates select="term[not(info/ref[@obj-type!='Unknown'])]"/>


          Or adding an if statement in your term[info/ref] template



          <xsl:template match="term[info/ref]">
          <xsl:if test="not(info/ref[@obj-type!='Unknown'])">
          <xsl:value-of select="@id"/>
          <xsl:text>,</xsl:text>
          <xsl:value-of select="name"/>
          <xsl:text>,</xsl:text>
          <xsl:text>
          </xsl:text>
          </xsl:if>

          </xsl:template>






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 15 '18 at 17:38









          NeskuNesku

          4231412




          4231412












          • It works. Thank you so much for taking your time to go through this code. I knew it was something that simple. I tried to use an IF but couldn't properly construct it in XSLT terms. Thanks again.

            – mistervela
            Nov 16 '18 at 10:11

















          • It works. Thank you so much for taking your time to go through this code. I knew it was something that simple. I tried to use an IF but couldn't properly construct it in XSLT terms. Thanks again.

            – mistervela
            Nov 16 '18 at 10:11
















          It works. Thank you so much for taking your time to go through this code. I knew it was something that simple. I tried to use an IF but couldn't properly construct it in XSLT terms. Thanks again.

          – mistervela
          Nov 16 '18 at 10:11





          It works. Thank you so much for taking your time to go through this code. I knew it was something that simple. I tried to use an IF but couldn't properly construct it in XSLT terms. Thanks again.

          – mistervela
          Nov 16 '18 at 10:11



















          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%2f53323550%2fxslt-how-to-select-siblings-with-a-condition%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







          這個網誌中的熱門文章

          How to read a connectionString WITH PROVIDER in .NET Core?

          Node.js Script on GitHub Pages or Amazon S3

          Museum of Modern and Contemporary Art of Trento and Rovereto