tags:

views:

682

answers:

3

I would like to select all descendant but "blog" nodes. For the example, only subtree should appear on output. I'm trying this xsl code:

<xsl:template match="rdf:RDF">
    <xsl:copy>    
        <xsl:copy-of select="descendant::*[not(descendant::blog)]"/>
    </xsl:copy>
  </xsl:template>

for this xml:

<rdf:RDF>
  <profesor rdf:ID="profesor_39">
    <nombre rdf:datatype="http://www.w3.org/2001/XMLSchema#string"
    >Augusto</nombre>
  </profesor>
  <blog rdf:ID="blog_41">
    <entradas>
      <entrada_blog rdf:ID="entrada_blog_42">
        <etiquetas>
          <tecnologia rdf:ID="tecnologia_49">
            <termino rdf:datatype="http://www.w3.org/2001/XMLSchema#string"
            >Atom</termino>
          </tecnologia>
        </etiquetas>
        <autor>
          <alumno rdf:ID="alumno_38">
            <nombre rdf:datatype="http://www.w3.org/2001/XMLSchema#string"
            >Jesus</nombre>
          </alumno>
        </autor>
      </entrada_blog>
    </entradas>
    <autores rdf:resource="#alumno_38"/>
    <direccion rdf:datatype="http://www.w3.org/2001/XMLSchema#string"
    >http://tfg1.unex.es/10comunidad/wordpress/&lt;/direccion&gt;
  </blog>
</rdf:RDF>

What am I missing? "blog" nodes are still printed on the output. Thank you.

+1  A: 

To omit blog and all its children:

<xsl:template match="RDF">
    <xsl:copy-of select="child::node()[name() != 'blog']"/>
</xsl:template>

To omit blog but still o/p its children:

<xsl:template match="RDF">
    <xsl:copy-of select="descendant::node()[name() != 'blog']"/>
</xsl:template>
Rashmi Pandit
The second one explodes the result; it's probably not what you'd want. It would copy all of <entradas> and its descendants (including <entrada_blog>, etc.); *then* it would copy <entrada_blog> and its descendants. So you'd end up with lots of duplicate sub-trees. A modified identity transform (see my answer) would give you the most power in either case.
Evan Lenz
+3  A: 

Here's a complete solution:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

  <!-- By default, recursively copy all nodes unchanged -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- But strip out <blog> -->
  <xsl:template match="blog"/>

  <!-- If you want to strip out just the <blog> start and end tags, use this instead:
  <xsl:template match="blog">
    <xsl:apply-templates/>
  </xsl:template>
  -->

</xsl:stylesheet>
Evan Lenz
A: 

The condition not(descendant::blog) excludes any node that have a descendant named "blog".

So if you have:

<blog id="1">
  <test id="1.1">
    <blog id="1.1.1" />
  </test>
</blog>
<blog id="2">
  <test id="2.1" />
</blog>

It will exclude <blog id="1"> and <test id="1.1">, because these nodes both have <blog id="1.1.1"> as a descendant.

But it won't exclude <blog id="1.1.1"> or <blog id="2"> because they don't have any descendant named "blog"

Also note that your select of descendant::*[not(descendant::blog)] will output <test id="2.1"> twice: once within <blog id="2">, and once again by itself.

For a complete solution, the one suggested by Evan Lenz (identity transform with a blank overriding template for "blog" nodes) is probably the one that gives the result you wanted.

ckarras