3

I'm working with a XML requests whereby I need to change the attribute value of an element if another attribute value is equal to one or more values. Xpath can't update the XML itself (so I understand) and I have been looking at XSL but it's quite complicated and I don't normally work in XML.

This is a cut down version of the XML I'm working wth :

<t6:Catalogue xmlns:t6="http://xxx.yy.com">
    <t6:Items>
        <t6:Item />
        <t6:Item />
        <t6:Item />
    </t6:Items>
    <t6:Mappings>
        <t6:Mapping action="ADD_NEW" type="MAP"></t6:Mapping>
        <t6:Mapping action="ADD_NEW" type="FOO"></t6:Mapping>
        <t6:Mapping action="ADD_NEW" type="CAR"></t6:Mapping>
        <t6:Mapping action="ADD_NEW" type="PLANE"></t6:Mapping>
        <t6:Mapping action="ADD_NEW" type="MAP"></t6:Mapping>
    </t6:Mappings>
</t6:Catalogue>

I need to change the action from ADD_NEW to UPDATE_OLD in the Mappings block if type equals PLANE or CAR.

I have been looking at peoples' other examples of XSL and trying to wrap my head around how to start it but cannot. The tool I am using supports XSL and has a custom piece of software where I can drop an XSL template into it and it will apply it to the XML message I specify.

But I'm not sure where to start -- at risk of sounding like, "Please do my work for me, SO users", if someone could give me at least a starting point of how I first point to my structure and then how to change a value IF x = y.

Thanks everyone.

isaw
  • 31
  • 2

2 Answers2

3

If you only want to change this certain attribute you could go with an identity transform and manage @action with a template:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t6="http://xxx.yy.com"
    exclude-result-prefixes="xs"
    version="2.0">

        <!-- Deleted template match="/" -->

        <xsl:template match="*|@*">
                <xsl:copy>
                        <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
        </xsl:template>

        <xsl:template match="@action[../@type = 'PLANE' or ../@type = 'CAR']">
                <xsl:attribute name="action" select="'ADD_OLD'"/>
        </xsl:template>
</xsl:stylesheet>
FelHa
  • 1,043
  • 11
  • 24
3

The idea behind XSLT is to traverse the input XML tree and produce new output from the XML nodes.

In its most fundamental form, this is done through template matching.

  • write templates that match certain nodes based on a condition, and
  • write code that applies templates to nodes (related read).

The most basic template there is is the identity template.

<xsl:template match="node() | @*">
  <xsl:copy>
    <xsl:apply-templates select="node() | @*" />
  </xsl:copy>
</xsl:template>

It is very unspecific; it can match any node and simply recursively calls itself, copying anything it finds. This produces an output document that is identical to the input, hence the name.

It gets more interesting when you add more specific templates, because XSLT will pick a better-matching template over a less specific one.

Like this one, which specifically only matches @action attributes that belong to an element that have @type PLANE or CAR. Instead of copying, it creates a new attribute node with the same name but a different value.

<xsl:template match="@action[../@type = 'PLANE' or ../@type = 'CAR']">">
  <xsl:attribute name="action">ADD_OLD</xsl:attribute>
</xsl:template>

These two templates together achieve what you want. The generic one copies everything as-is, unless a more specific one matches a certain node.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • +1 Also, a shorter match expression could also be used `@action[../@type = ('PLANE', 'CAR')]` – Mads Hansen Apr 14 '18 at 14:05
  • @Mads Not in XSLT 1.0, though. I tried to be as compatible as possible for this simple task, especially since I don't know the restrictions of what the OP can use. – Tomalak Apr 14 '18 at 14:11
  • That got it! Thank you for the response and especially the explanation. – isaw Apr 14 '18 at 14:13
  • 1
    Makes sense. So many things are easier in 2.0+. It's too bad the default processors in browsers, Java, etc. make it difficult for people to move on and relegated to 1.0... – Mads Hansen Apr 14 '18 at 14:16