Reputation:
Using XSLT 3.0,
I have as input the following XML:
<?xml ="1.0" encoding="UTF-8"?>
<TABLE NAME="TABLE.DB">
<DATA RECORDS="2">
<RECORD ID="1">
<RECNO>1</RECNO>
<SEQ>0</SEQ>
<DATE>17/12/1999 2:44:08 μμ</DATE>
<ID>12/11/2015 3:15:25 μμ</ID>
<ORDER>10355</ORDER>
<CN>PL</CN>
<PROPERTY>06</PROPERTY>
</RECORD>
<RECORD ID="2">
<RECNO>2</RECNO>
<SEQUENCE>0</SEQUENCE>
<DATE>17/12/1999 2:44:08 μμ</DATE>
<ID>12/11/2015 3:15:25 μμ</ID>
<ORDER>000026672</ORDER>
<CN>PL 300 L</CN>
</RECORD>
<RECORD ID="3">
<RECNO>3</RECNO>
<SEQUENCE>0</SEQUENCE>
<DATE>17/12/1999 2:44:08 μμ</DATE>
<ID>12/11/2015 3:15:25 μμ</ID>
<NUMBER>10357</NUMBER>
<CN>PL 300 L</CN>
<PROPERTY>0</PROPERTY>
</RECORD>
</DATA>
</TABLE>
given values used for matching: (i use \t to define the tab separated nature of my input file)
"10355"\t"PL"
"000026672"\t"PL 300 L"
i need to insert to all records that do not already have a PROPERTY tag, with the value of 06
Desired result:
<?xml ="1.0" encoding="UTF-8"?>
<TABLE NAME="TABLE.DB">
<DATA RECORDS="2">
<RECORD ID="1">
<RECNO>1</RECNO>
<SEQ>0</SEQ>
<DATE>17/12/1999 2:44:08 μμ</DATE>
<ID>12/11/2015 3:15:25 μμ</ID>
<ORDER>10355</ORDER>
<CN>PL</CN>
<PROPERTY>06</PROPERTY>
</RECORD>
<RECORD ID="2">
<RECNO>2</RECNO>
<SEQUENCE>0</SEQUENCE>
<DATE>17/12/1999 2:44:08 μμ</DATE>
<ID>12/11/2015 3:15:25 μμ</ID>
<ORDER>000026672</ORDER>
<CN>PL 300 L</CN>
<PROPERTY>06</PROPERTY>
</RECORD>
<RECORD ID="3">
<RECNO>3</RECNO>
<SEQUENCE>0</SEQUENCE>
<DATE>17/12/1999 2:44:08 μμ</DATE>
<ID>12/11/2015 3:15:25 μμ</ID>
<NUMBER>10357</NUMBER>
<CN>PL 300 L</CN>
</RECORD>
</DATA>
</TABLE>
What i have tried, adds the element property, even if it is already there, so i end up with two elements PROPERTY, in the same node, if it already exists. Could you give me an example implementation, i use SAXON latest release (9.8)
xsl: which adds an element, even when one exists:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="xsl exsl xs">
<xsl:output method="xml" version="1.0" indent="yes" encoding="utf-8" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="//*[local-name() = 'RECORD ID']">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:choose>
<xsl:when test="not(PRODUCT)">
<PRODUCT><xsl:value-of select="98"/></PRODUCT>
</xsl:when>
<xsl:otherwise>
<xsl:copy><xsl:value-of select="98"/></xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Have been using the solution suggested with my real data, (which differ a lot from the example), and i face the following issue:
How could i also have a report that would let me know, which of the additions while they were to be done, according to the input file, were not inserted?
Upvotes: 0
Views: 182
Reputation: 31011
Your solution requires a few changes:
The template shoud match RECORD
, not RECORD ID
(ID
is an
attribute which takes no part in any decision).
Your general concept is OK:
<RECORD>
),RECORD
,PROPERTY
(not PRODUCT
) element is absent (in the
current RECORD
),PROPERTY
element with the required value,</RECORD>
).I removed the otherwise
part (not needed) and changed choose
to
a single if
..
As you specified XSLT 3.0, even the identity template can be
replaced with (a bit shorter) on-no-match="shallow-copy"
.
I also added version
to your source XML. Otherwise it is not well-formed.
So the whole script can look like below:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="RECORD">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:if test="not(PROPERTY)">
<PROPERTY>06</PROPERTY>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Tested on http://xsltfiddle.liberty-development.net/
Upvotes: 0
Reputation: 163595
A few observations:
(a) in your sample output, the PROPERTY element has been deleted from record 3. I can't see anything in your description of requirements that explains why.
(b) in your requirements statement, the sentence "i need to insert to all records that do not already have a PROPERTY tag, with the value of 06" is ambiguous. I would read this as saying that if there is a PROPERTY 'tag' (correctly, element) with a value other than 06 then you should insert another PROPERTY element, but that seems to contradict what you say elsewhere.
(c) your code has a template rule with match="//*[local-name() = 'RECORD ID']"
. You can delete the "//" at the start of a match pattern, it's redundant. More importantly, no element will ever have a local name equal to "RECORD ID" - element names cannot include spaces. So the template rule will never match anything.
(d) assuming that this template rule was intended to match RECORD elements, you certainly don't want the xsl:copy inside the xsl:otherwise, as this will create a nested copy of the whole RECORD.
(e) you've asked for an XSLT 3.0 solution but there's nothing in your problem that requires XSLT 3.0, and in fact your own stylesheet says version="2.0".
(f) I can't see what role the tab-separated parameter file plays in any of this.
In short, there's an awful lot of clarification needed before anyone can start to write any code.
Upvotes: 0