I use saxon 11he
file 1.xml describes all objects:
<?xml version="1.0" encoding="utf-8"?>
<ADDRESSOBJECTS>
<OBJECT OBJECTID="105037985" NAME="OTHER PARENT" LEVEL="2" STARTDATE="2022-07-20" ENDDATE="2079-06-06" ISACTIVE="1" />
<OBJECT OBJECTID="1171388" NAME="PARENT" LEVEL="2" STARTDATE="1900-01-01" ENDDATE="2079-06-06" ISACTIVE="1" />
<OBJECT OBJECTID="1171421" NAME="CHILD 1" LEVEL="6" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<OBJECT OBJECTID="1171502" NAME="CHILD 2" LEVEL="6" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<OBJECT OBJECTID="1171612" NAME="CHILD 3" LEVEL="4" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<OBJECT OBJECTID="1171731" NAME="CHILD 4" LEVEL="4" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<OBJECT OBJECTID="1171761" NAME="CHILD 5" LEVEL="6" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
</ADDRESSOBJECTS>
file 2.xml describes the hierarchical dependency:
<?xml version="1.0" encoding="utf-8"?>
<ITEMS>
<ITEM OBJECTID="1170420" PARENTOBJID="1171380" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<ITEM OBJECTID="1170423" PARENTOBJID="1171380" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<ITEM OBJECTID="1171421" PARENTOBJID="1171388" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<ITEM OBJECTID="1171421" PARENTOBJID="1171388" STARTDATE="2001-01-01" ENDDATE="2004-12-26" ISACTIVE="0" />
<ITEM OBJECTID="1171502" PARENTOBJID="1171388" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<ITEM OBJECTID="1171612" PARENTOBJID="1171388" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<ITEM OBJECTID="1171731" PARENTOBJID="1171388" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
<ITEM OBJECTID="1171761" PARENTOBJID="1171388" STARTDATE="2004-12-27" ENDDATE="2079-06-06" ISACTIVE="1" />
</ITEMS>
I need to build a tree from file 1 objects by hierarchy from file 2
I'm stuck even at the first level, there are 4-5 levels in total, and there are two hierarchy files, there is another independent hierarchy (but it doesn't matter) First, how to return to the context of file 1 in for-each? (see below xsl file) Secondly, how to select a node in for-each by the 2nd file from the 1st file and work with its attributes? Because, I need to copy a lot more attributes and pull them in the way that I have, this is every new search and, accordingly, an increase execution time. Thirdly, it is necessary to sort by @NAME (from the 1st file), although it is not necessary, but interesting.
I made some crutches, I assume that everything is done differently:
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
>
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:variable name="objectid">
<xsl:value-of
select="//OBJECT[@LEVEL='2' and @ISACTIVE='1' and starts-with(@NAME, 'PARENT')]/@OBJECTID"/>
</xsl:variable>
<xsl:template match="/">
<ROOT OBJECTID="{$objectid}">
<xsl:for-each select="document('2.xml')//ITEM[@PARENTOBJID=$objectid and @ISACTIVE='1']">
<xsl:variable name="childid">
<xsl:value-of select="@OBJECTID"/>
</xsl:variable>
<xsl:variable name="childname">
<xsl:value-of
select="document('1.xml')//OBJECT[@OBJECTID=$childid and @ISACTIVE='1']/@NAME"/>
</xsl:variable>
<xsl:variable name="childlevel">
<xsl:value-of
select="document('1.xml')//OBJECT[@OBJECTID=$childid and @ISACTIVE='1']/@LEVEL"/>
</xsl:variable>
<ELEMENT OBJECTID="{$childid}" NAME="{$childname}" LEVEL="{$childlevel}" />
</xsl:for-each>
</ROOT>
</xsl:template>
</xsl:transform>
output:
<?xml version="1.0" encoding="UTF-8"?>
<ROOT OBJECTID="1171388">
<ELEMENT OBJECTID="1171421" NAME="CHILD 1" LEVEL="6"/>
<ELEMENT OBJECTID="1171502" NAME="CHILD 2" LEVEL="6"/>
<ELEMENT OBJECTID="1171612" NAME="CHILD 3" LEVEL="4"/>
<ELEMENT OBJECTID="1171731" NAME="CHILD 4" LEVEL="4"/>
<ELEMENT OBJECTID="1171761" NAME="CHILD 5" LEVEL="6"/>
</ROOT>
PS: In general, i need to get something like this structure.
<REGION>
<DISTRICT>
<MUNICIPALDISTRICT>
<LOCALITY>
<DRIVEWAY>
<HOUSE>
</HOUSE>
</DRIVEWAY>
</LOCALITY>
</MUNICIPALDISTRICT>
</DISTRICT>
</REGION>
the element of each nested level is called by its own name
PPS: I hope I've made my confused thoughts clear.
CodePudding user response:
Use a key e.g. <xsl:key name="child" match="ITEM" use="@PARENTOBJID"/>
and then you can follow e.g. key('child', @OBJECTID, doc('2.xml'))
to find element children of the currently processed ITEM
.
Trying to use that it seems you need a second key to look back in the main document:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:key name="child" match="ITEM" use="@PARENTOBJID"/>
<xsl:key name="object" match="OBJECT" use="@OBJECTID"/>
<xsl:variable name="doc1" select="/"/>
<xsl:template match="/">
<xsl:apply-templates select="ADDRESSOBJECTS/OBJECT[@LEVEL = 2]"/>
</xsl:template>
<xsl:template match="OBJECT[@LEVEL = 2]">
<ROOT>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('object', @OBJECTID, $doc1)"/>
</ROOT>
</xsl:template>
<xsl:template match="OBJECT">
<ELEMENT>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('object', @OBJECTID, $doc1)"/>
</ELEMENT>
</xsl:template>
<xsl:param name="doc2" select="doc('2.xml')"/>
</xsl:stylesheet>
I guess you want to filter out some attributes with an empty template.