xsl-list
[Top] [All Lists]

Re: [xsl] Copy all attributes except except some

2014-06-18 20:33:10
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(_at_)exselt(_dot_)net <
xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:


On 11-6-2014 1:05, Philipp Kursawe phil(_dot_)kursawe(_at_)gmail(_dot_)com 
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


--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--
<Prev in Thread] Current Thread [Next in Thread>