Re: [xsl] Copy all attributes except except some

Subject: Re: [xsl] Copy all attributes except except some
From: "Philipp Kursawe phil.kursawe@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 19 Jun 2014 01:32:57 -0000
Thanks @all for your help so far.

My input XML looks like this:
<InspectionExt result="1" charge="20" expert="HAHA" ...>
  <Defects>
  <Defect how="Wie07" component="4A03" reinspection="todo"/>
  <Defect how="Wie20" component="2A11" reinspection="nok"/>
  <Defect where="Wo07" how="Wie09" component="8A05" reinspection="ok"/>
    <Defect component="2A03"/>
  </Defects>
  <Obligations>
  </Obligations>
  <Photo>
  </Photo>
  <Photo>
  </Photo>
</InspectionExt>

The resulting XML should contain only 2 attributes from "InspectionExt" in
case result="10" or "11" otherwise all attributes and "Obligations",
"Defects" but no "Photo"
Also when copying the Defects/Defect items, only those with
"not(@reinspection='ok'" should be copied over. No "Defects" element should
be created if nothing from source xml is copied.
The resulting "Defect" element must not contain the "reinspection"
attribute.

That's what I came up with after your suggestions:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"; xmlns:xs="
http://www.w3.org/2001/XMLSchema"; xmlns:fn="
http://www.w3.org/2005/xpath-functions";>
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

  <xsl:template match="InspectionExt">
    <xsl:element name="ns2:InspectionReportInput" namespace="
http://somenamespace";>
 <xsl:choose>
<xsl:when test="@result eq '10' or @result eq '11'">
 <xsl:copy-of select="@result"/>
<xsl:copy-of select="@expert"/>
</xsl:when>
 <xsl:otherwise>
      <xsl:copy-of select="@*[not(@signed)]"/>
      <xsl:for-each select="Defects">
        <xsl:element name="Defects">
          <xsl:for-each select="Defect[not(@reinspection='ok')]">
            <xsl:element name="Defect">
              <xsl:copy-of select="@*[not(@reinspection)]"/>
            </xsl:element>
          </xsl:for-each>
        </xsl:element>
      </xsl:for-each>
      <xsl:copy-of select="Obligations"/>
      </xsl:otherwise>
</xsl:choose>

    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

Unfortunately this does not remove the "reinspection" attributes in the
copied "Defect" elements.
The resulting part of the XML looks like this:
<Defects>
  <Defect how="Wie07" component="4A03" reinspection="todo"/>
  <Defect how="Wie20" component="2A11" reinspection="nok"/>
  <Defect component="2A03"/>
</Defects>
The "Defect" element that was marked with "reinspection=ok" is not
included, which is correct. But the other elements also should not have the
"reinspection" attribute.

Also I like the idea, to put my special attributes that are not part of the
original schema in their own namespace. Then none of those attributes (and
elements) belonging to my "private" namespace should be copied over to the
resulting XML.

How does the XSLT look to you experts?

Thanks
Phil



On Wed, Jun 11, 2014 at 1:49 AM, Abel Braaksma (Exselt) abel@xxxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

>
> On 11-6-2014 1:05, Philipp Kursawe phil.kursawe@xxxxxxxxx wrote:
> > I am using:
> > <xsl:copy-of select="@*[local-name() != 'signed']"/>
>
> Because of the way != works, this will usually give you all attributes
> regardless.
>
> > I assume I have to make a long list of "or local-name() != 'otherAtt'"
> > to exclude all my attributes that should not be copied over. Or is
> > there a smarter way to just define a list of attributes that are not
> > copied?
>
> There are many ways. "Long list" sounds to me that you want to configure
> it somewhere explicitly, or look for a pattern in the local-name. Also,
> in most XML I have seen, attributes are in no-namespace, but I haven't
> seen your input so I'm not sure. I would use the except keyword, which
> works just the way you expect it to work:
>
> <xsl:copy-of select="@* except (@signed, @unsigned)"/>
>
> Or if you cannot use nametests, you can continue to using local-name(),
> but you should reverse the test and use '=' on a sequence, instead of
> '!=', like this:
>
> <xsl:copy-of select="@*[not(local-name() = ('signed', 'unsigned'))]"/>
>
> Though, if you do have attributes in namespaces and if you do know the
> names you want to exclude, I can advice you to use nametests instead.
> Consider your input looks like:
>
> <foo x:signed="true" y:signed="false" z:signed="always" />
>
> And you the prefixes x, y, z are each bound to different namespaces, you
> will remove too many attributes if you use local-name(). Instead, write
> it as follows:
>
> <xsl:copy-of select="@* except (@z:signed, @y:signed)"/>
>
> which will leave x:signed in place and remove the rest.
>
> There are many more ways in XSLT to tackle this issue. To help you
> better for your situation, it would help us help you if you show us a
> (small, but complete) sample of your input data.
>
> Cheers,
>
> Abel Braaksma
> Exselt XSLT 3.0 streaming processor
> http://exselt.net

Current Thread