Copy only the nodes where the name contains "a"

584 Views Asked by At

I have an asigment that basically read like this :

I have this XMl structure

<?xml-stylesheet href="monfichier.xsl" type="text/xsl" ?>
<a>
<ab x="x"><b>Test</b><a>z</a></ab>
<z x="x"><a>z</a></z>
</a>

And I need to copy all node where the name contains "a" but where the parent also contains an "a". In my example, that would mean skipping the node

 <z x="x"><a>z</a></z> 

Since the parent's name contains "z" and not "a". Here is what my output should look like.

<a>
<ab x="x"><a>z</a></ab>

This assignment is a two part one, the first part is to write XSLT code that do not uses xsl:element and the second which won't use xsl:copy. I'm still at the first part, so xsl:copy is okay.

Here is what I've come up with, looking around the internet.

<?xml version="1.0" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//*[contains(name(), 'a')]">
  <xsl:copy>
    <xsl:apply-templates />
  </xsl:copy>
</xsl:template>
</xsl:stylesheet>   

The problem is that this code does not ignore the node... I can't seems to get my head around this.

Thank you

EDIT

With Potame's anwser I was able to figure out the second part of the assignment, which is to do the same thing without any xsl:copy.

Here is the code, it works like a charm.

<?xml version="1.0" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="*[contains(name(), 'a')]/*[contains(name(), 'a')] | /*[contains(name(), 'a')]">
     <xsl:element name="{local-name()}">
       <xsl:choose>
         <xsl:when test="@x">
           <xsl:attribute name="x" >
             <xsl:value-of select="@x" />
           </xsl:attribute>
         </xsl:when>
       </xsl:choose>
       <xsl:apply-templates />
     </xsl:element>
  </xsl:template>
  <xsl:template match="*" >
  </xsl:template>
</xsl:stylesheet>   
1

There are 1 best solutions below

1
On BEST ANSWER

Here's a small stylesheet that will lead you to the expected result.

<?xml version="1.0" ?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="*[contains(name(), 'a')]/*[contains(name(), 'a')] | /*[contains(name(), 'a')]">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
  </xsl:template>

</xsl:stylesheet>

However I think it's not really clearly stated for the case of the text within an element that has to be skipped.

Morover, how should we process such a case:

<a>
  <z x="x">
    <aa>z
      <ade>Another case</ade>
    </aa>
  </z>
</a>

<z> is to be skipped, but should we do to his contents? Regarding your rules, <ade> should be output because it a child of <aa>, but <aa> is not processed at all because its parent is z (skipped).