user1709612
user1709612

Reputation:

XSLT: How to select siblings with a condition

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>&#10;</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>&#10;</xsl:text>

</xsl:template>

</xsl:stylesheet>

I hope it's clear.

Upvotes: 0

Views: 670

Answers (1)

Nesku
Nesku

Reputation: 501

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>&#10;</xsl:text>
    </xsl:if>

</xsl:template>

Upvotes: 0

Related Questions