XSLT element selection based on Choose not working - xslt

I have the following XML:
<Document>
<Row>
<KEY>NIKE|JB|APPAREL|MENS</KEY>
<Period>Nov-21</Period>
</Row>
<Row>
<KEY>FASCINATE|JB|ACCESSORIES|LADIES</KEY>
<Matches>
<Row>
<KEY>FASCINATE|JB|ACCESSORIES|LADIES</KEY>
<Period>Nov-22</Period>
</Row>
</Matches>
</Row>
</Document>
I want to use XSLT to return the nested /Matches/Row/Period when the Document/Row/Period is undefined (as it is in the second Row of the XML)
So I have the following XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http://exampleincludednamespace.com/"
exclude-result-prefixes="ns">
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:template match="/">
<Document>
<xsl:for-each select="/Document/Row">
<xsl:variable name="period" select="/Period" />
<xsl:choose>
<xsl:when test="$period = null">
<xsl:copy>
<xsl:copy-of select="KEY | /Matches/Row/Period" />
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="KEY | Period" />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Document>
</xsl:template>
</xsl:stylesheet>
But it returns the following output:
<Document>
<Row>
<KEY>NIKE|JB|APPAREL|MENS</KEY>
<Period>Nov-21</Period>
</Row>
<Row>
<KEY>FASCINATE|JB|ACCESSORIES|LADIES</KEY>
</Row>
</Document>
(Note how it is not returning the nested /Matches/Row/Period in the second /Row.
I expect to get the following output:
<Document>
<Row>
<KEY>NIKE|JB|APPAREL|MENS</KEY>
<Period>Nov-21</Period>
</Row>
<Row>
<KEY>FASCINATE|JB|ACCESSORIES|LADIES</KEY>
<Period>Nov-22</Period>
</Row>
</Document>
What am I doing wrong?

undefined or null are not checked in XSLT/XPath using expression = null, you would rather use (for node-sets) <xsl:when test="expression"> e.g. <xsl:when test="Period"> that there is at least one Period child element for the context node or test="not(Period)" to check there is no Period child.
In the end I would suggest to use template matching based on the identity transformation template and put any conditions into match pattern (predicates), but that is a different issue.

Got it working with this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http://exampleincludednamespace.com/"
exclude-result-prefixes="ns">
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:template match="/">
<Document>
<xsl:for-each select="/Document/Row">
<xsl:choose>
<xsl:when test="not(Period)">
<xsl:copy>
<xsl:copy-of select="KEY | Matches/Row/Period" />
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="KEY | Period" />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Document>
</xsl:template>
</xsl:stylesheet>
Thanks to #MartinHonnen's guidance.

I believe it could be simply:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Document">
<xsl:copy>
<xsl:for-each select="Row">
<xsl:copy>
<xsl:copy-of select="KEY | descendant::Period[1]" />
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

convert XSLT 2.0 to 1.0

I have the following solution in XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/rows">
<xsl:copy>
<xsl:for-each-group select="row" group-starting-with="row[item='****************']">
<xsl:variable name="title-item" select="preceding-sibling::row[1]/item" />
<xsl:for-each select="current-group()[starts-with(item[1], '#')]">
<row>
<xsl:copy-of select="$title-item, *"/>
</row>
</xsl:for-each>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
as for-each-group is not supported in XSLT 1.0
I want to convert it into XSLT 1.0 version.
Declare e.g.
<xsl:key name="group" match="row[not(item = '****************')]" use="generate-id(preceding-sibling::row[item='****************'][1])"/>
as a top-level element, then instead of <xsl:for-each-group select="row" group-starting-with="row[item='****************']"> try
<xsl:for-each select="row[item='****************']">
<xsl:variable name="group" select="key('group', generate-id())"/>
<xsl:variable name="title-item" select="preceding-sibling::row[1]/item" />
<xsl:for-each select="$group[starts-with(item[1], '#')]">
<row>
<xsl:copy-of select="$title-item | *"/>
</row>
</xsl:for-each>
</xsl:for-each>
But we really need to see some input sample structure plus the wanted result. And I might be overlooking some XSLT/XPath 2 only stuff I have used despite trying to write XSLT 1.

Generate new group based on node value in XSLT

I am new to XSLT, and I am trying to create new group based on node value eventType so if eventType is alert, create new group event.
I am checking for last sibling
Input XML
<?xml version="1.0" encoding="UTF-8"?><Rowsets >
<Row>
<eventId>2</eventId>
<plantId>1020</plantId>
<workCenter>WC1</workCenter>
<eventType>alert</eventType>
<eventText>Downtime</eventText>
<eventDesc>WorkcenterDown</eventDesc>
</Row>
<Row>
<eventId>3</eventId>
<plantId>1021</plantId>
<workCenter>WC1</workCenter>
<eventType>alert</eventType>
<eventText>Downtime</eventText>
<eventDesc>WorkcenterDown</eventDesc>
</Row>
<Row>
<eventId>4</eventId>
<plantId>1020</plantId>
<workCenter>WC2</workCenter>
<eventType>incident</eventType>
<eventText>eventtext</eventText>
<eventDesc>failed</eventDesc>
</Row>
<Row>
<plantId>1020</plantId>
<workCenter>WC2</workCenter>
<eventType>incident</eventType>
<eventText>Text</eventText>
<eventDesc>failed</eventDesc>
</Row>
</Rowsets>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<Rowsets>
<Alert>
<element>
<Title>Downtime:DIA01</Title>
<eventDesc>WorkcenterDown</eventDesc>
</element>
<element>
<Title>Downtime:DIA01</Title>
<eventDesc>WorkcenterDown</eventDesc>
</element>
</Alert>
<Incident>
<element>
<Title>YAT < 60%:DIA01</Title>
<eventDesc>7 Parts in 60 minutes have failed</eventDesc>
</element>
<element>
<Title>YAT < 60%:DIA01</Title>
<eventDesc>7 Parts in 60 minutes have failed</eventDesc>
</element>
</Incident>
</Rowsets>
Based on eventType, I want to generate group.
I am using this XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8"
indent="yes" />
<xsl:template match="/">
<Rowsets>
<Rowset>
<xsl:variable name="Type" select="'alert'"/>
<xsl:for-each select="/Rowsets/Rowset/Row">
<xsl:choose>
<xsl:when test="$Type = eventType">
<element>
<xsl:variable name="text" select="eventText"/>
<xsl:variable name="WC" select="workCenter"/>
<Title><xsl:value-of select="concat($text,':',$WC)" /></Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:when>
<xsl:otherwise>
<element>
<xsl:variable name="text" select="eventText"/>
<xsl:variable name="WC" select="workCenter"/>
<Title><xsl:value-of select="concat($text,':',$WC)" /></Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Rowset>
</Rowsets>
</xsl:template>
</xsl:stylesheet>
Need help in generating id and key based on eventType
This is a grouping problem - and a rather trivial one at that. In XSLT 2.0 you could do simply:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="Rowsets">
<Rowsets>
<xsl:for-each-group select="Row" group-by="eventType">
<xsl:element name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<element>
<Title>
<xsl:value-of select="eventText, workCenter" separator=":"/>
</Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</Rowsets>
</xsl:template>
</xsl:stylesheet>
Alternatively, with only two possible types, you could do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="Rowsets">
<Rowsets>
<Alert>
<xsl:apply-templates select="Row[eventType='alert']"/>
</Alert>
<Incident>
<xsl:apply-templates select="Row[eventType='incident']"/>
</Incident>
</Rowsets>
</xsl:template>
<xsl:template match="Row">
<element>
<Title>
<xsl:value-of select="eventText"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="workCenter"/>
</Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:template>
</xsl:stylesheet>
This is assuming you don't mind creating a group even if it is empty. Otherwise you would do:
<xsl:template match="Rowsets">
<Rowsets>
<xsl:variable name="alerts" select="Row[eventType='alert']"/>
<xsl:variable name="incidents" select="Row[eventType='incident']"/>
<xsl:if test="$alerts">
<Alert>
<xsl:apply-templates select="Row[eventType='alert']"/>
</Alert>
</xsl:if>
<xsl:if test="$incidents">
<Incident>
<xsl:apply-templates select="Row[eventType='incident']"/>
</Incident>
</xsl:if>
</Rowsets>
</xsl:template>
P.S. Note that XML is case-sensitive: <Alert> is not the same as <alert>.

Append new xml node under existing xml nodes using xslt

I am trying to append a new XML node under existing XML node but i wasn't able to achieve the desired result.
Please find my below XML,
<Root>
<Row>
<A1>0</A1>
<A2>1</A2>
<Preferred_First_Name>aaaa</Preferred_First_Name>
<Preferred_Last_Name>yyyy</Preferred_Last_Name>
<location>xxxx</location>
<ID>12345</ID>
</Row>
</Root>
I want to modify the above XML in such a way that Preferred_First_Name, Preferred_Last_Name and location node need to be under a new XML tag "Data".
The desired output should be like below,
<Root>
<Row>
<A1>0</A1>
<A2>1</A2>
<Data>
<Preferred_First_Name>aaaa</Preferred_First_Name>
<Preferred_Last_Name>yyyy</Preferred_Last_Name>
<location Descriptor="xxxx">
<ID type="ID">xxxx</ID>
<ID type="LocationID">xxxx</ID>
</location>
</Data>
<ID>12345</ID>
</Row>
</Root>
Can someone please help?
you can use below
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet xmlns:xalan="http://xml.apache.org/xalan" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="Root">
<xsl:element name="Root">
<xsl:call-template name="Row" />
</xsl:element>
</xsl:template>
<xsl:template name="Row">
<xsl:element name="Row">
<xsl:copy-of select="Row/A1"/>
<xsl:copy-of select="Row/A2"/>
<xsl:element name="Data">
<xsl:copy-of select="Row/Preferred_First_Name"/>
<xsl:copy-of select="Row/Preferred_Last_Name"/>
<xsl:element name="location">
<xsl:attribute name="Descriptor">
<xsl:value-of select="Row/location"/>
</xsl:attribute>
<xsl:element name="ID">
<xsl:attribute name="type">
<xsl:value-of select="'ID'"/>
</xsl:attribute>
<xsl:value-of select="Row/location"/>
</xsl:element>
<xsl:element name="ID">
<xsl:attribute name="type">
<xsl:value-of select="'LocationID'"/>
</xsl:attribute>
<xsl:value-of select="Row/location"/>
</xsl:element>
</xsl:element>
<xsl:copy-of select="Row/ID"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Please let me know this helps you
If it is okay to put <ID> after <Data> mentioned by Tim C, then the optimized solution can be:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row">
<Row>
<xsl:apply-templates select="child::node()[not(self::Preferred_First_Name or self::Preferred_Last_Name
or self::location)]" />
<Data>
<xsl:apply-templates select="child::node()[self::Preferred_First_Name or self::Preferred_Last_Name
or self::location]"/>
</Data>
</Row>
</xsl:template>
</xsl:stylesheet>

XSLT Convert attribute to element and copy value from an other elemen

I have XML data like this
<ABC version="1.0">
<XYZ>
<ROWSET ROWS="00001">
<ROWDEF>
<COLUMN ID="ACCT_ID" LEN="016" NULL="Y"/>
<COLUMN ID="AGNT_ID" LEN="004" NULL="Y"/>
<COLUMN ID="CUST_EXTR_ID" LEN="024" NULL="Y"/>
<COLUMN ID="PI_ID" LEN="019" NULL="Y"/>
<COLUMN ID="PRIN_ID" LEN="004" NULL="Y"/>
<COLUMN ID="SYS_ID" LEN="004" NULL="Y"/>
</ROWDEF>
<ROW>
<C>6369921501000060</C>
<C>0000</C>
<C>C13093102141063422034238</C>
<C>6369921501000060 </C>
<C>1500</C>
<C>9008</C>
</ROW>
<ROW>
<C>6369921501000061</C>
<C>0001</C>
<C>C13093102141063422034231</C>
<C>6369921501000060 </C>
<C>1501</C>
<C>9001</C>
</ROW>
</ROWSET>
</XYZ>
</ABC>
And I'm trying to convert this into
<?xml version="1.0" encoding="utf-8"?>
<ABC version="1.0">
<XYZ RC="0067">
<ROWSET ROWS="00001">
<ROWDEF>
<ACCT_ID>6369921501000060</ACCT_ID>
<AGNT_ID>0000</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034238</CUST_EXTR_ID>
<PI_ID>6369921501000060</PI_ID>
<PRIN_ID>1500</PRIN_ID>
<SYS_ID>9008</SYS_ID>
</ROWDEF>
<ROWDEF>
<ACCT_ID>6369921501000061</ACCT_ID>
<AGNT_ID>0001</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034231</CUST_EXTR_ID>
<PI_ID>6369921501000060</PI_ID>
<PRIN_ID>1501</PRIN_ID>
<SYS_ID>9001</SYS_ID>
</ROWDEF>
</ROWSET>
</XYZ>
</ABC>
I have looked around and tried few things but it is not working.
Can someone help me with this.
Below is my XSLT. Thanks in advance.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="COLUMN">
<xsl:element name="{#ID}">
<xsl:copy>
<xsl:apply-templates select="node()"></xsl:apply-templates>
</xsl:copy>
<xsl:apply-templates />
<!--<xsl:call-template name="value"></xsl:call-template>-->
</xsl:element>
</xsl:template>
<!--
<xsl:template match="ROW" name="value">
<xsl:copy>
<xsl:apply-templates select="node()"></xsl:apply-templates>
</xsl:copy>
</xsl:template>
-->
</xsl:stylesheet>
This stylesheet will mostly do what you want, but I cannot fathom how to generate the attribute for <XYZ RC="0067">.
For each ROWSET it comes across it saves the ROWDEF element in a variable, copies all attribute nodes, and then processes each ROW element. The position of each C element in the ROW is caclulated, and the COLUMN in the corresponding position within the stored ROWDEF element is used to fetch an element name from the ID attribute.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="ROWSET">
<xsl:variable name="columns" select="ROWDEF/COLUMN"/>
<xsl:copy>
<xsl:apply-templates select="#*" />
<xsl:for-each select="ROW">
<ROWDEF>
<xsl:for-each select="C">
<xsl:variable name="pos" select="position()"/>
<xsl:element name="{$columns[$pos]/#ID}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</ROWDEF>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
output
<?xml version="1.0" encoding="utf-8"?>
<ABC version="1.0">
<XYZ>
<ROWSET ROWS="00001">
<ROWDEF>
<ACCT_ID>6369921501000060</ACCT_ID>
<AGNT_ID>0000</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034238</CUST_EXTR_ID>
<PI_ID>6369921501000060 </PI_ID>
<PRIN_ID>1500</PRIN_ID>
<SYS_ID>9008</SYS_ID>
</ROWDEF>
<ROWDEF>
<ACCT_ID>6369921501000061</ACCT_ID>
<AGNT_ID>0001</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034231</CUST_EXTR_ID>
<PI_ID>6369921501000060 </PI_ID>
<PRIN_ID>1501</PRIN_ID>
<SYS_ID>9001</SYS_ID>
</ROWDEF>
</ROWSET>
</XYZ>
</ABC>

Delete Foreign Keys

I have DB tables stored in XML format that have a FK based on two columns (Table2 has FK to Table1 based on ID and TYPE).
Table1.xml
<Table>
<Row>
<ID>1</ID>
<TYPE>A</TYPE>
<CONFIG>Y</CONFIG>
...
</Row>
<Row>
<ID>2</ID>
<TYPE>A</TYPE>
<CONFIG>Z</CONFIG>
...
</Row>
<Row>
<ID>1</ID>
<TYPE>B</TYPE>
<CONFIG>X</CONFIG>
...
</Row>
<Row>
<ID>3</ID>
<TYPE>A</TYPE>
<CONFIG>Z</CONFIG>
...
</Row>
</Table>
Table2.xml
<Table>
<Row>
<ID>1</ID>
<TYPE>A</TYPE>
...
</Row>
<Row>
<ID>2</ID>
<TYPE>A</TYPE>
...
</Row>
<Row>
<ID>1</ID>
<TYPE>B</TYPE>
...
</Row>
<Row>
<ID>3</ID>
<TYPE>A</TYPE>
...
</Row>
</Table>
I will have two XSLT files to delete rows in each XML file. Table2 will be processed first. I want to delete the row in Table2 where when joined with Table1 CONFIG=Z (ie, delete rows where (ID=2 and Type=A) and (ID=3 and Type=A), but I need to figure this out only knowing I want to delete records where CONFIG=Z). Table1 will then be processed to delete rows where CONFIG=Z, which I was able to figure out.
I think the XSLT that will be applied to Table2 needs to read in Table1 XML (xsl:variable name="table1Rows" select="document('Table1.xml')/Table/Row"/>). After that I'm lost on how to delete rows in Table2 where CONFIG=Z. I've tried several things based on examples I saw, but couldn't get anything to work.
With XSLT 2.0 define a key and cross-reference the elements, then simply do an identity transformation to copy nodes plus a template that suppresses the copying for those Row elements where the key function call finds a Row in the other document with the CONFIG being Z:
<xsl:variable name="table1" select="doc('Table1.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row[key('r-by-id-and-type', concat(ID, '|', TYPE), $table1)/CONFIG = 'Z']"/>
[edit] For completeness, I tested the following complete sample with both Saxon 9.4 as well as AltovaXML successfully:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:variable name="table1" select="doc('table1.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row[key('r-by-id-and-type', concat(ID, '|', TYPE), $table1)/CONFIG = 'Z']"/>
</xsl:stylesheet>
On request in comment I also add an XSLT 1.0 stylesheet:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:variable name="table1" select="document('test2012100102.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row">
<xsl:variable name="this" select="."/>
<xsl:for-each select="$table1">
<xsl:if test="not(key('r-by-id-and-type', concat($this/ID, '|', $this/TYPE))/CONFIG = 'Z')">
<xsl:copy-of select="$this"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Martin's solution is correct, given the original question and should be accepted.
In reference to the OP's request for an additional XSLT 1.0 solution, here is a polyglot. This style-sheet, a minor variation of Martin's solution, works on XSLT 2.0 processors and probably most XSLT 1.0 processors.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:variable name="table1" select="doc('table1.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="#*|node()" name="ident">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="Row"
use-when="number(system-property('xsl:version')) < 2" priority="2">
<xsl:variable name="row" select="." />
<xsl:variable name="id-type" select="concat(ID, '|', TYPE)" />
<xsl:for-each select="$table1">
<xsl:if test="not( key('r-by-id-and-type', $id-type))">
<xsl:for-each select="$row">
<xsl:call-template name="ident" />
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template
match="Row"
use-when="number(system-property('xsl:version')) >= 2" priority="1">
<xsl:if test="not( key('r-by-id-and-type', concat(ID, '|', TYPE), $table1))">
<xsl:call-template name="ident" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Caveat
This style-sheet was not tested.
The answers provided by Martin work and are probably the best solutions possible. For XSLT 1.0 I had come up with the following that seems to run faster, but is not as elegant. For this solution I knew that the only possible TYPE for CONFIG=Z is 'A'. (Note there could be a typo below since I'm running the XSLT on another machine and retyped it here with the mock column names/values.)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="table1_Z_rows" select="document('table1.xml')/Table/Row[CONFIG='Z']"/>
<xsl:template match="Row">
<xsl:choose>
<xsl:when test="TYPE != 'A'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:if test="not(ID = $table1_Z_rows/ID)">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>