Navigating to the Nested child Attribute and Merge with the another Element - xslt

Here i am stuck with the XSLT transformation as i am very new and started learning.
Input XML
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345678"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
<SHOW_ELEMENT ID="2">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345666"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
<ALTERNATIVE_SHOW_LIST>
<SHOW ID="54321">
<SHOW_INFO>xxxa</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="3"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="4"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="5"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
<SHOW ID="54322">
<SHOW_INFO>xxxb</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="6"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="7"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</ALTERNATIVE_SHOW_LIST>
</SHOW>
OUTPUT XML :
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="2"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="3"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="4"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="5"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="6"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="7"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
<ALTERNATIVE_SHOW_LIST>
<SHOW ID="54321">
<SHOW_INFO>xxxa</SHOW_INFO>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
<SHOW ID="54322">
<SHOW_INFO>xxxb</SHOW_INFO>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</ALTERNATIVE_SHOW_LIST>
</SHOW>
</SHOW_LIST>
I am able to navigate till Alternative_show_list and couldnt copy the SHOW_ELEMENTS and merge with the main SHOW_ELEMENT_LIST.
Anyone kindly help me in performing this
Another output of the same input file
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="2"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="3"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="4"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="5"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="6"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="7"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</SHOW_LIST>
Now i am trying for this kind of output.
New Output XML
<?xml version="1.0" encoding="UTF-8"?>
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345678"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
<SHOW_ELEMENT ID="2">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345666"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
<SHOW_ELEMENT ID="3"/>
<SHOW_ELEMENT ID="4"/>
<SHOW_ELEMENT ID="5"/>
<SHOW_ELEMENT ID="6"/>
<SHOW_ELEMENT ID="7"/>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</SHOW_LIST>

This simple stylesheet will do the trick:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<!-- identity template -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- get all the SHOW_ELEMENT nodes -->
<xsl:template match="SHOW//SHOW_ELEMENT_LIST[not(ancestor::ALTERNATIVE_SHOW_LIST)]">
<SHOW_ELEMENT_LIST>
<xsl:copy-of select="..//SHOW_ELEMENT"/>
</SHOW_ELEMENT_LIST>
</xsl:template>
<!-- delete all SHOW_ELEMENT_LIST under ALTERNATIVE_SHOW_LIST -->
<xsl:template match="SHOW//SHOW_ELEMENT_LIST[ancestor::ALTERNATIVE_SHOW_LIST]"/>
</xsl:stylesheet>

<xsl:template match="ALTERNATIVE_SCHEDULE_LIST"/>
This helps for the second output XML to delete the ATERNATIVE_SCHEDULE_LIST element.
Please correct me if there is any other solution

Related

xslt 1 : check if node contains any value from list

I need to tranform a XML document from one format to a other, and that is all dandy. Now the hard part is that I need to check all lines for a status code, and need to return true/false depend if any code element have any of this codes.
<xml>
<line>
<id>1</id>
<code>109</code>
</line>
<line>
<id>2</id>
<code>065</code>
</line>
<line>
<id>3</id>
<code>405</code>
</line>
<line>
<id>4</id>
<code>101</code>
</line>
</xml>
The document I tranform to keep a copy of all line element, but have a extra field, where is set to true/false depend if the any code is in the list.
So I need to compare this list of data to every code and return true if just one of them is in the list
"101","102","103","104","105","106","107","108","109","110","111"
Is there any fix mode to make this so I don't need 11 compare stament ?
Ohh and the output look some thing like
<System>
<Route>true</Route> <!-- will be false if the <code> from the first document is not in the list of elements -->
<Status>
<ID>1</ID>
<Code>109</Code>
</Status>
<Status>
<ID>2</ID>
<Code>065</Code>
</Status>
<Status>
<ID>3</ID>
<Code>405</Code>
</Status>
<Status>
<ID>4</ID>
<Code>101</Code>
</Status>
<System>
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pCodeList" select="'101,102,103,104,105,106,107,108,109,110,111'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<System>
<Route>
<xsl:value-of select=
"boolean(/*/*/code
[contains(concat(',', $pCodeList, ','), concat(',', ., ',')
)
]
)"/>
</Route>
<xsl:apply-templates/>
</System>
</xsl:template>
<xsl:template match="line">
<Status><xsl:apply-templates/></Status>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<xml>
<line>
<id>1</id>
<code>109</code>
</line>
<line>
<id>2</id>
<code>065</code>
</line>
<line>
<id>3</id>
<code>405</code>
</line>
<line>
<id>4</id>
<code>101</code>
</line>
</xml>
produces the wanted, correct result:
<System>
<Route>true</Route>
<Status>
<id>1</id>
<code>109</code>
</Status>
<Status>
<id>2</id>
<code>065</code>
</Status>
<Status>
<id>3</id>
<code>405</code>
</Status>
<Status>
<id>4</id>
<code>101</code>
</Status>
</System>
When the same transformation (above) is applied on this XML document:
<xml>
<line>
<id>1</id>
<code>509</code>
</line>
<line>
<id>2</id>
<code>065</code>
</line>
<line>
<id>3</id>
<code>405</code>
</line>
<line>
<id>4</id>
<code>501</code>
</line>
</xml>
it again produces the wanted, correct result:
<System>
<Route>false</Route>
<Status>
<id>1</id>
<code>509</code>
</Status>
<Status>
<id>2</id>
<code>065</code>
</Status>
<Status>
<id>3</id>
<code>405</code>
</Status>
<Status>
<id>4</id>
<code>501</code>
</Status>
</System>

XPath expression to exclude some child nodes

I have this source XML tree:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>
<bar>
<baz>
<item>
<methods>
<item>
<id>1</id>
</item>
</methods>
<id>1</id>
</item>
<item>
<methods>
<item>
<id>19</id>
</item>
</methods>
<id>2</id>
</item>
</baz>
</bar>
</foo>
<bar_method>
<root>
<bla id="1">
<methods>
<method id="1">
<calc md="ck" />
<tm m="14" />
<price_list>
<price mse="0">
<ins re="0" />
</price>
</price_list>
</method>
<method id="2">
<calc md="qck" />
<tm m="4" />
<price_list>
<price mse="1">
<ins re="0" />
</price>
</price_list>
</method>
</methods>
</bla>
<bla id="2">
<methods>
<method id="19">
<calc md="dd" />
<tm m="3" />
<price_list>
<price mse="01">
<ins re="0" />
</price>
</price_list>
</method>
</methods>
</bla>
</root>
</bar_method>
</root>
Now I need to place fragment of this tree in variable using XPath. The fragment should look like this:
<bla id="1">
<methods>
<method id="1">
<calc md="ck" />
<tm m="14" />
<price_list>
<price mse="0">
<ins re="0" />
</price>
</price_list>
</method>
</methods>
</bla>
<bla id="2">
<methods>
<method id="19">
<calc md="dd" />
<tm m="3" />
<price_list>
<price mse="01">
<ins re="0" />
</price>
</price_list>
</method>
</methods>
</bla>
These are bla nodes excluding method nodes, id attributes of which missing in /root/foo/bar/baz/item/methods/item/id. I use following expression but it selects all nodes with duplicates:
<xsl:variable name="meth" select="/root/bar_method/root//*[not(name() = 'method' and count(/root/foo/bar/baz//methods/item[id = #id]) = 0)]" />
XPath can only select nodes, it cannot change them. That is to say, the children and descendants of the nodes you select will always be exactly as they were in the source document.
If you want to create a tree that's different from the input tree, you need XSLT or XQuery.
Looks like you want all the bla elements and just the first methods/method element within each of them. Is that right?
You can't do that in a single XPath expression because you can only restrict the elements being selected - you can't filter out some of their descendants as well. But it is possible using templates.
This stylesheet creates the variable $meth and outputs it using copy-of.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:variable name="meth">
<xsl:apply-templates select="root/bar_method/root/bla"/>
</xsl:variable>
<xsl:copy-of select="$meth"/>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="methods">
<xsl:copy>
<xsl:apply-templates select="method[1]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
output
<bla id="1">
<methods>
<method id="1">
<calc md="ck"/>
<tm m="14"/>
<price_list>
<price mse="0">
<ins re="0"/>
</price>
</price_list>
</method>
</methods>
</bla>
<bla id="2">
<methods>
<method id="19">
<calc md="dd"/>
<tm m="3"/>
<price_list>
<price mse="01">
<ins re="0"/>
</price>
</price_list>
</method>
</methods>
</bla>

Grouping multiple elements with same name

This is an extension to the question I asked earlier - XSLT 1.0 Grouping with multiple elements with same name
The output format has changed and hence reposting.
I have an XML that looks like -
<resultset>
<hit>
<content>
<ITEM>
<TITLE>Office Cleaning1</TITLE>
<DESCRIPTION>blah blah blah</DESCRIPTION>
<Hierarchy>level1A~level2A~level3A</Hierarchy>
<Hierarchy>level1B~level2B~level3B</Hierarchy>
</ITEM>
</content>
</hit>
<hit>
<content>
<ITEM>
<TITLE>Office Cleaning2</TITLE>
<DESCRIPTION>blah blah blah</DESCRIPTION>
<Hierarchy>level1A~level2A~level3B</Hierarchy>
</ITEM>
</content>
</hit>
<hit>
<content>
<ITEM>
<TITLE>Office Cleaning3</TITLE>
<DESCRIPTION>blah blah blah</DESCRIPTION>
<Hierarchy>level1A~level2B~level3C</Hierarchy>
</ITEM>
</content>
</hit>
<hit>
<content>
<ITEM>
<TITLE>Office Cleaning4</TITLE>
<DESCRIPTION>blah blah blah</DESCRIPTION>
<Hierarchy>level1A~level2B~level3B</Hierarchy>
<Hierarchy>level1A~level2B~level3C</Hierarchy>
</ITEM>
</content>
</hit>
<hit>
<content>
<ITEM>
<TITLE>Office Cleaning5</TITLE>
<DESCRIPTION>blah blah blah</DESCRIPTION>
<Hierarchy>level1B~level2B~level3B</Hierarchy>
</ITEM>
</content>
</hit>
</resultset>
Note that there are multiple hierarchy elements which is a concatenated string of level1~level2~level3 I am looking to transform this into something like this -
<TREE>
<LEVELS>
<LEVEL1 name="level1A">
<LEVEL2 name="level2A">
<LEVEL3 name="level3A">
<ITEM Name="Office Cleaning1"/>
</LEVEL3>
<LEVEL3 name="level3B">
<ITEM Name="Office Cleaning2"/>
</LEVEL3>
</LEVEL2>
<LEVEL2 name="level2B">
<LEVEL3 name="level3B">
<ITEM Name="Office Cleaning4"/>
</LEVEL3>
<LEVEL3 name="level3C">
<ITEM Name="Office Cleaning3"/>
<ITEM Name="Office Cleaning4"/>
</LEVEL3>
</LEVEL2>
</LEVEL1>
<LEVEL1 name="level1B">
<LEVEL2 name="level2B">
<LEVEL3 name="level3B">
<ITEM Name="Office Cleaning1"/>
<ITEM Name="Office Cleaning5"/>
</LEVEL3>
</LEVEL2>
</LEVEL1>
</TREE>
Basically each item has multiple hierarchy associated with it. I need to group them together and each levels to be grouped together as well.
I can actually change the values in the HIERARCHY element in the input XML to any format that might be easier to extract. For e.g. I can make it look like LEVEL1:level1A~LEVEL2:level2A~LEVEL3:level3A
but I cannot add new elements.
I got it working myself. Ignore the extra namespaces. I edited the hierarchy field to have format of level1:value~level2:value~level3:value for ease of substring.
I am sure there is a better way but this works for me.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:autn="http://schemas.autonomy.com/aci/">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="TOPLEVEL" match="autnresponse/responsedata/autn:hit/autn:content/DOCUMENT/HIERARCHY" use="substring-before(substring-after(.,'LEVEL1:'),'~')"/>
<xsl:key name="MIDLEVEL" match="autnresponse/responsedata/autn:hit/autn:content/DOCUMENT/HIERARCHY" use="substring-before(substring-after(.,'LEVEL2:'),'~')"/>
<xsl:key name="BOTTOMLEVEL" match="autnresponse/responsedata/autn:hit/autn:content/DOCUMENT/HIERARCHY" use="substring-before(substring-after(.,'LEVEL3:'),'~')"/>
<xsl:template match="/">
<TREE>
<xsl:for-each select="autnresponse/responsedata/autn:hit/autn:content/DOCUMENT/HIERARCHY[generate-id() = generate-id(key('TOPLEVEL',substring-before(substring-after(.,'LEVEL1:'),'~') )[1])]">
<xsl:variable name="TOP" select="substring-before(substring-after(.,'LEVEL1:'),'~')"/>
<LEVEL1>
<xsl:attribute name="name"><xsl:value-of select="substring-after($TOP,'+')"/></xsl:attribute>
<xsl:attribute name="id"><xsl:value-of select="substring-before($TOP,'+')"/></xsl:attribute>
<xsl:for-each select="//autnresponse/responsedata/autn:hit/autn:content/DOCUMENT/HIERARCHY[substring-before(substring-after(.,'LEVEL1:'),'~')=$TOP and generate-id() = generate-id(key('MIDLEVEL',substring-before(substring-after(.,'LEVEL2:'),'~') )[1])]">
<xsl:variable name="MID" select="substring-before(substring-after(.,'LEVEL2:'),'~')"/>
<LEVEL2>
<xsl:attribute name="name"><xsl:value-of select="substring-after($MID,'+')"/></xsl:attribute>
<xsl:attribute name="id"><xsl:value-of select="substring-before($MID,'+')"/></xsl:attribute>
<xsl:for-each select="//autnresponse/responsedata/autn:hit/autn:content/DOCUMENT/HIERARCHY[substring-before(substring-after(.,'LEVEL1:'),'~')=$TOP and substring-before(substring-after(.,'LEVEL2:'),'~')=$MID and generate-id() = generate-id(key('BOTTOMLEVEL',substring-before(substring-after(.,'LEVEL3:'),'~') )[1])]">
<xsl:variable name="BOTTOM" select="substring-before(substring-after(.,'LEVEL3:'),'~')"/>
<LEVEL3>
<xsl:attribute name="name"><xsl:value-of select="substring-after($BOTTOM,'+')"/></xsl:attribute>
<xsl:attribute name="id"><xsl:value-of select="substring-before($BOTTOM,'+')"/></xsl:attribute>
<xsl:apply-templates select="//HIERARCHY[substring-before(substring-after(.,'LEVEL1:'),'~')=$TOP and substring-before(substring-after(.,'LEVEL2:'),'~')=$MID and substring-before(substring-after(.,'LEVEL3:'),'~')=$BOTTOM]"/>
</LEVEL3>
</xsl:for-each>
</LEVEL2>
</xsl:for-each>
</LEVEL1>
</xsl:for-each>
</TREE>
</xsl:template>
<xsl:template match="HIERARCHY">
<ITEM>
<xsl:attribute name="name"><xsl:value-of select="../DRETITLE"/></xsl:attribute>
<xsl:attribute name="id"><xsl:value-of select="../ID"/></xsl:attribute>
</ITEM>
</xsl:template>
</xsl:stylesheet>

how to get some documents from one xml

I would like to get distinct documents from my xml on multiple levels.
My xml file:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<line id="0">
<Info><![CDATA[Header]]></Info>
<documentNUM><![CDATA[DOC1]]></documentNUM>
<Code><![CDATA[AS22]]></Code>
</line>
<line id="1">
<Info><![CDATA[Line]]></Info>
<Position><![CDATA[1]]></Position>
<Number><![CDATA[7361]]></Number>
</line>
<line id="2">
<Info><![CDATA[Line]]></Info>
<Position><![CDATA[2]]></Position>
<Number><![CDATA[7362]]></Number>
</line>
<line id="3">
<Info><![CDATA[Header]]></Info>
<documentNUM><![CDATA[DOC2]]></documentNUM>
<Code><![CDATA[AS22]]></Code>
</line>
<line id="4">
<Info><![CDATA[Line]]></Info>
<Position><![CDATA[1]]></Position>
<Number><![CDATA[3623]]></Number>
</line>
<line id="5">
<Info><![CDATA[Header]]></Info>
<documentNUM><![CDATA[DOC1]]></documentNUM>
<Code><![CDATA[AS22]]></Code>
</line>
<line id="6">
<Info><![CDATA[Line]]></Info>
<Position><![CDATA[1]]></Position>
<Number><![CDATA[3623]]></Number>
</line>
</document>
From this xml I should get two documents,
for it I use key function:
<xsl:key name="kNext" match="line[starts-with(Info,'H')]" use="concat(starts-with(Info,'H'), '+', documentNUM)"/>
And for both documents 3 and 1 lines.
Needed result:
<result>
<Group>
<Message>
<document>
<documentNUM>DOC1</documentNUM>
<Lines>
<Line>
<LineNumber>1</LineNumber>
<Number>7361</Number>
<Code>AS22</Code>
</Line>
<Line>
<LineNumber>2</LineNumber>
<Number>7362</Number>
<Code>AS22</Code>
</Line>
<Line>
<LineNumber>3</LineNumber>
<Number>3623</Number>
<Code>AS22</Code>
</Line>
</Lines>
</document>
</Message>
</Group>
<Group>
<Message>
<document>
<documentNUM>DOC2</documentNUM>
</document>
<Line>
<LineNumber>1</LineNumber>
<Number>3623</Number>
<Code>AS22</Code>
</Line>
</Lines>
</Message>
</Group>
</result>
I'm stuck to finding lines. For both documents calculate the same lines. Please give me some advice how to get correct answer.
P.S. Please correct my question if it needed.
Here is a complete XSLT 1.0 solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kFollowing" match="line[not(documentNUM)]"
use="generate-id(preceding-sibling::line
[documentNUM]
[1]
)"/>
<xsl:key name="kLineByDocNum" match="line"
use="documentNUM"/>
<xsl:template match=
"line
[documentNUM
and
generate-id()
=
generate-id(key('kLineByDocNum', documentNUM)[1])
]">
<Group>
<Message>
<document>
<documentNUM>
<xsl:value-of select="documentNUM"/>
</documentNUM>
<Lines>
<xsl:apply-templates mode="inGroup" select=
"key('kLineByDocNum', documentNUM)"/>
</Lines>
</document>
</Message>
</Group>
</xsl:template>
<xsl:template match="line" mode="inGroup">
<xsl:apply-templates mode="inGroup2"
select="key('kFollowing', generate-id())">
<xsl:with-param name="pCode" select="Code"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="line" mode="inGroup2">
<xsl:param name="pCode"/>
<xsl:variable name="vcurDocNum" select=
"preceding-sibling::line
[documentNUM][1]
/documentNUM
"/>
<xsl:variable name="vPos" select=
"count(preceding-sibling::line
[not(documentNUM)]
[preceding-sibling::line
[documentNUM][1]
/documentNUM
=
$vcurDocNum
]
) +1"/>
<Line>
<LineNumber><xsl:value-of select="$vPos"/></LineNumber>
<xsl:copy-of select="Number"/>
<Code><xsl:value-of select="$pCode"/></Code>
</Line>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<document>
<line id="0">
<Info>Header</Info>
<documentNUM>DOC1</documentNUM>
<Code>AS22</Code>
</line>
<line id="1">
<Info>Line</Info>
<Position>1</Position>
<Number>7361</Number>
</line>
<line id="2">
<Info>Line</Info>
<Position>2</Position>
<Number>7362</Number>
</line>
<line id="3">
<Info>Header</Info>
<documentNUM>DOC2</documentNUM>
<Code>AS22</Code>
</line>
<line id="4">
<Info>Line</Info>
<Position>1</Position>
<Number>3623</Number>
</line>
<line id="5">
<Info>Header</Info>
<documentNUM>DOC1</documentNUM>
<Code>AS22</Code>
</line>
<line id="6">
<Info>Line</Info>
<Position>1</Position>
<Number>3623</Number>
</line>
</document>
the wanted, correct result is produced:
<Group>
<Message>
<document>
<documentNUM>DOC1</documentNUM>
<Lines>
<Line>
<LineNumber>1</LineNumber>
<Number>7361</Number>
<Code>AS22</Code>
</Line>
<Line>
<LineNumber>2</LineNumber>
<Number>7362</Number>
<Code>AS22</Code>
</Line>
<Line>
<LineNumber>3</LineNumber>
<Number>3623</Number>
<Code>AS22</Code>
</Line>
</Lines>
</document>
</Message>
</Group>
<Group>
<Message>
<document>
<documentNUM>DOC2</documentNUM>
<Lines>
<Line>
<LineNumber>1</LineNumber>
<Number>3623</Number>
<Code>AS22</Code>
</Line>
</Lines>
</document>
</Message>
</Group>
This looks like a grouping problem. If you have XSLT 2.0 available, use for-each-group / group-starting-with. Then you don't need a key:
<result>
<xsl:for-each-group select="line"
group-starting-with="line[starts-with(Info,'H')]">
<Group>
<Message>
<document>
<documentNUM>
<xsl:value-of select="current-grouping-key()/documentNUM" />
</documentNUM>
</document>
<xsl:apply-templates select="current-group()
[not(starts-with(Info, 'H'))]" />
etc.
If you want more detail, let me know.

Ancestors' same-name siblings

<corpus>
<header id="1">
<file>
<info>
<title id="A" />
</info>
</file>
</header>
<TEI>
<header id="2">
<file>
<info>
<title id="B" />
</info>
</file>
</header>
<header id="3">
<file>
<info>
<record>
<title id="C" />
</record>
</info>
</file>
</header>
<header id="4">
<file>
</file>
</header>
</TEI>
</corpus>
$list is a set of <title> nodes.
The depth of <title> varies, but is always somewhere under a <header>. The depth of <header> varies, but its depth from root is always the same for all nodes in a given $list.
Given a $list, I need a for-each loop that loops through headers.
When the only node in $list is title A, I need to loop only through header 1.
When the nodes in $list are titles B and C, I need to loop through headers 2, 3 and 4.
Use:
$list/ancestor::header[1]/../header
XSLT - based verification:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vList1" select=
"/*/header[1]/*/*/title"/>
<xsl:variable name="vList2" select=
"/*/TEI//title"/>
<xsl:template match="/">
<xsl:copy-of select="$vList1"/>
====
<xsl:copy-of select="$vList2"/>
====
<xsl:copy-of select=
"$vList1/ancestor::header[1]/../header"/>
====
<xsl:copy-of select=
"$vList2/ancestor::header[1]/../header"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<corpus>
<header id="1">
<file>
<info>
<title id="A" />
</info>
</file>
</header>
<TEI>
<header id="2">
<file>
<info>
<title id="B" />
</info>
</file>
</header>
<header id="3">
<file>
<info>
<record>
<title id="C" />
</record>
</info>
</file>
</header>
<header id="4">
<file>
</file>
</header>
</TEI>
</corpus>
the XPath expressions are evaluated and the wanted in each case header elements are selected and output:
<title id="A"/>
====
<title id="B"/>
<title id="C"/>
====
<header id="1">
<file>
<info>
<title id="A"/>
</info>
</file>
</header>
====
<header id="2">
<file>
<info>
<title id="B"/>
</info>
</file>
</header>
<header id="3">
<file>
<info>
<record>
<title id="C"/>
</record>
</info>
</file>
</header>
<header id="4">
<file>
</file>
</header>