Peter Sondag
Peter Sondag

Reputation: 15

XSLT copy everything under a specific element, but change value of some attributes

I'm struggling with an xslt issue where I need to copy everything under a specific element, but I also need to change the value of one of the attributes.

Here is my XML:

<?xml version="1.0" encoding="UTF-8"?>
<message>
  <datetime datum="20190318" time="154933"/>
  <information environment="A" formula="AA" database_action="I"/>
  <identification versionnumber="1" publication_type="MESSAGE_NAME"/>
  <content>
    <PickWave>
      <Pick pickID="1" groupID="11802182" groupType="orderPick" eachQuantity="1" sourceLocation="P5F.021.01-004" destinationLocation="E1A">
        <Container containerID="11802182">
          <ContainerType>CRATE</ContainerType>
        </Container>
        <Product productID="593000" description="593000-DESCRIPTION" unitOfMeasure="Box" weightUnitOfMeasure="g" dimensionUnitOfMeasure="mm" length="230" width="115,5" height="95" weight="312,1">
          <Identifiers>
            <Identifier label="barcode">
              <AllowedValues>8713776016527</AllowedValues>
            </Identifier>
          </Identifiers>
        </Product>
        <Data>
          <containerType>CRATE</containerType>
        </Data>
      </Pick>
      <Pick pickID="2" groupID="11802182" groupType="orderPick" eachQuantity="1" sourceLocation="P5F.022.01-001" destinationLocation="E1A">
        <Container containerID="11802182">
          <ContainerType>CRATE</ContainerType>
        </Container>
        <Product productID="600318" description="600318-DESCRIPTION" unitOfMeasure="Bag" weightUnitOfMeasure="g" dimensionUnitOfMeasure="mm" length="160" width="160" height="230" weight="26,5">
          <Identifiers>
            <Identifier label="barcode">
              <AllowedValues>8711247936732</AllowedValues>
            </Identifier>
          </Identifiers>
        </Product>
        <Data>
          <containerType>CRATE</containerType>
        </Data>
      </Pick>
    </PickWave>
  </content>
  <error exitcode="" message=""/>
</message>

And here is my XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
        <xsl:copy copy-namespaces="no">
            <xsl:message>
                <xsl:value-of select="name(.)"/>
            </xsl:message>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- When attribute matches @weight, @lenght, @width or @height, replace comma (EU) with dots (US) as decimal seperator -->
    <xsl:template match="*:Product/@weight | *:Product/@length | *:Product/@width | *:Product/@height">
        <xsl:variable name="vAttr" select="name(.)"/>
        <xsl:attribute name="{$vAttr}" select="translate(.,',','.')"/>
    </xsl:template> 

</xsl:stylesheet>

I understand that my first template matches every element/attribute and thus creates the <message> until <content> elements, but how do I get it to match every element and attribute from the PickWave element en copy all those elements?

And this would be my desired output:

<?xml version="1.0" encoding="UTF-8"?>
<PickWave>
    <Pick pickID="1" groupID="11802182" groupType="orderPick" eachQuantity="1" sourceLocation="P5F.021.01-004" destinationLocation="E1A">
        <Container containerID="11802182">
            <ContainerType>CRATE</ContainerType>
        </Container>
        <Product productID="593000" description="593000-DESCRIPTION" unitOfMeasure="Box" weightUnitOfMeasure="g" dimensionUnitOfMeasure="mm" length="230" width="115.5" height="95" weight="312.1">
            <Identifiers>
                <Identifier label="barcode">
                    <AllowedValues>8713776016527</AllowedValues>
                </Identifier>
            </Identifiers>
        </Product>
        <Data>
            <containerType>CRATE</containerType>
        </Data>
    </Pick>
    <Pick pickID="2" groupID="11802182" groupType="orderPick" eachQuantity="1" sourceLocation="P5F.022.01-001" destinationLocation="E1A">
        <Container containerID="11802182">
            <ContainerType>CRATE</ContainerType>
        </Container>
        <Product productID="600318" description="600318-DESCRIPTION" unitOfMeasure="Bag" weightUnitOfMeasure="g" dimensionUnitOfMeasure="mm" length="160" width="160" height="230" weight="26.5">
            <Identifiers>
                <Identifier label="barcode">
                    <AllowedValues>8711247936732</AllowedValues>
                </Identifier>
            </Identifiers>
        </Product>
        <Data>
            <containerType>CRATE</containerType>
        </Data>
    </Pick>
</PickWave>

Upvotes: 1

Views: 1243

Answers (2)

Alejandro
Alejandro

Reputation: 1882

but how do I get it to match every element and attribute from the PickWave

If I'm getting you right, you want to change those attributes in any descendant element of PickWave element. So you need:

<xsl:template match="*:PickWave//@weight
                    |*:PickWave//@lenght
                    |*:PickWave//@width
                    |*:PickWave//@height">
    <xsl:attribute name="{name()}" select="translate(.,',','.')"/>
</xsl:template> 

Or if you want a pattern more in the XSLT 2.0 style

<xsl:template match="*:PickWave//@*[
                        some $a in ../(@weight|@lenght|@width|@height) 
                        satisfies $a is .
                     ]">
    <xsl:attribute name="{name()}" select="translate(.,',','.')"/>
</xsl:template> 

Upvotes: 1

Tim C
Tim C

Reputation: 70618

If you only want the PickWave elements in your output, one solution is to simply have a template matching the document node, and then select only the elements you wish to copy....

Try adding this template to your existing XSLT

<xsl:template match="/">
    <xsl:apply-templates select="message/content/PickWave" />
</xsl:template>

Upvotes: 1

Related Questions