2

Trying to remove all elements with attribute onlyChannels="print" from XML Using XQuery the element with onlyChannels="print" can be anywhere and at different levels.

Input XML

<?xml version="1.0" encoding="UTF-8"?>
<abstractGroup>
   <abstract type="main" xml:lang="en">
      <title type="main">Abstract</title>
      <p>900 000 ha along the test of north</p>
      <p onlyChannels="print">Abstract</p>
   </abstract>
   <abstract onlyChannels="online" type="main" xml:lang="es">
      <title type="main">Resumen</title>
      <p>La orsdft de los trópifdaa</p>
   </abstract>
   <full type="main" xml:lang="en">
      <p onlyChannels="print">full</p>
      <p>900 000 ha along the test of north‐east</p>
      <doc>
      <p onlyChannels="print"> do not print</p>
      <p> print </p>
      </doc>
   </full>
</abstractGroup>

expcted output XML

<abstractGroup>
   <abstract type="main" xml:lang="en">
      <title type="main">Abstract</title>
      <p>900 000 ha along the test of north</p>
   </abstract>
   <abstract onlyChannels="online" type="main" xml:lang="es">
      <title type="main">Resumen</title>
      <p>La orsdft de los trópifdaa</p>
   </abstract>
   <full type="main" xml:lang="en">
      <p>900 000 ha along the test of north‐east</p>
     <doc>
      <p> print </p>
      </doc>
   </full>
</abstractGroup>

I was trying this XQuery but it's only removing elements in the first level and without XML tags.

let $root:=  abstractGroup/*/*[not(self::*/@onlyChannels="print")]
return $root

what I got :

Abstract 
900 000 ha along the test of north 
Resumen 
La orsdft de los trópifdaa
900 000 ha along the test of north‐east

   do not print
   print

How I can print the xml tags and removing all elements with attribute onlyChannels="print"

Ahmad Al-Kurdi
  • 2,248
  • 3
  • 23
  • 39
  • 3
    Which XQuery processor is that? Does it support XQuery update? Or does it support (like Saxon 10 or 9) XSLT as well? In XSLT you could declare the identity transformation as the base template with e.g. `` and add an empty template `` to delete any such elements and you are done. – Martin Honnen Oct 04 '21 at 12:26
  • 4
    In XQuery Update, as supported by BaseX, for instance, all you need is `delete nodes //*[@onlyChannels = 'print']`. – Martin Honnen Oct 04 '21 at 13:13

1 Answers1

3

You could run it through a recursive typeswitch function to transform the XML:

declare function local:filter($nodes as node()*) as node()*
{
  for $n in $nodes return
  typeswitch ($n)
    case element () return 
      if ($n[@onlyChannels="print"]) 
      then local:filter($n/node()) 
      else element { node-name($n) } { $n/@*, local:filter($n/node())}
    default return $n
};

let $doc :=
<abstractGroup>
   <abstract type="main" xml:lang="en">
      <title type="main">Abstract</title>
      <p>900 000 ha along the test of north</p>
      <p onlyChannels="print">Abstract</p>
   </abstract>
   <abstract onlyChannels="online" type="main" xml:lang="es">
      <title type="main">Resumen</title>
      <p>La orsdft de los trópifdaa</p>
   </abstract>
   <full type="main" xml:lang="en">
      <p onlyChannels="print">full</p>
      <p>900 000 ha along the test of north‐east</p>
      <doc>
      <p onlyChannels="print"> do not print</p>
      <p> print </p>
      </doc>
   </full>
</abstractGroup>

return local:filter($doc)
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147