I have an below incoming XML request i want to remove empty node like "altname"
Incoming XML:
<saml2:Assertion Version="2.0" ID="SAML-727af5f8-6bd0-45f8-b9c0-c95e3c5da9f5" IssueInstant="2016-01-31T13:27:28Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:Issuer>ssodp</saml2:Issuer>
<saml2:AttributeStatement>
<saml2:Attribute Name="altname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml2:AttributeValue/>
</saml2:Attribute>
<saml2:Attribute Name="ID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml2:AttributeValue>5345435345</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
I have written below XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[ not(descendant-or-self::node()[normalize-space()]) and
not(descendant-or-self::*/#*[normalize-space()] and not(count(descendant-or-self::*/#*) = count(descendant-or-self::*/#xsi:nil)) ) ]">
<xsl:if test="local-name(.) = 'Envelope' or local-name(.) = 'Body' or local-name(.) = 'payload'">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
It's not working as expected.
I need the below XML output:
Desired XML Output:
<saml2:Assertion Version="2.0" ID="SAML-727af5f8-6bd0-45f8-b9c0-c95e3c5da9f5" IssueInstant="2016-01-31T13:27:28Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:Issuer>ssodp</saml2:Issuer>
<saml2:AttributeStatement>
<saml2:Attribute Name="ID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml2:AttributeValue>5345435345</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
Please let me know how to do this.
You were right in using the identity template.
Just filtering out the nodes you don't want will give you your desired result.
So just ignoring the nodes which have an empty saml2:AttributeValue/text()-node with a simple empty template is sufficient:
<xsl:template match="saml2:Attribute[normalize-space(saml2:AttributeValue/text()) = '']" />
So use this XSLT - which has only minor modifications compared to yours:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<!-- identity template -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- filter out the nodes with an empty 'saml2:AttributeValue' child -->
<xsl:template match="saml2:Attribute[normalize-space(saml2:AttributeValue/text()) = '']" />
</xsl:stylesheet>
Result:
<?xml version="1.0"?>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="SAML-727af5f8-6bd0-45f8-b9c0-c95e3c5da9f5" IssueInstant="2016-01-31T13:27:28Z">
<saml2:Issuer>ssodp</saml2:Issuer>
<saml2:AttributeStatement>
<saml2:Attribute Name="ID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml2:AttributeValue>5345435345</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
Related
I have multiple occurence nodes which need to be generated at output using XSLT transformation. Could you please help me on this.
Following XSLT code only generate one node occurrence only. Could you please help me with below XSLT code how to generate multiple nodes elements in Input XML
Input XML
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >
<soapenv:Body>
<ns1:getGenResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
<ns1:getGenReturn xsi:type="soapenc:Array" soapenc:arrayType="xsd:anyType[2]" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
</ns1:getGenReturn>
</ns1:getGenResponse>
<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Gen" xmlns:soapenc=http://schemas.xmlsoap.org/soap/encoding/>
<name xsi:type="xsd:string">ULM</name>
<mail xsi:type="xsd:string">ulm#gmail.com</mail>
</multiRef>
<multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns3:Gen" " xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<name xsi:type="xsd:string">ABC</name>
<mail xsi:type="xsd:string">abc#gmail.com</mail>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
XSLT Code used for this transformation
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" x
xmlns:response="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Output -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:if test="//soap:Body/multiRef">
<xsl:element name="getGenResponse">
<xsl:element name="getGenReturn">
<xsl:element name="name"><xsl:value-of select="//name"/></xsl:element>
<xsl:element name="mail"><xsl:value-of select="//mail"/></xsl:element>
</xsl:element>
</xsl:element>
</xsl:if>
</xsl:template>
<!-- 'Copy ' node -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output from above XSLT
<?xml version="1.0" encoding="UTF-8"?>
<getGenResponse>
<getGenReturn>
<name> ULM </name>
<mail>ulm#gmail.com<mail>
</getGenReturn>
/getGenResponse>
Output expected
<?xml version="1.0" encoding="UTF-8"?>
<getGenResponse>
<getGenReturn>
<name> ULM </name>
<mail>ulm#gmail.com<mail>
</getGenReturn>
<getGenReturn>
<name>ABC</name>
<mail>abc#gmail.com<mail>
</getGenReturn>
/getGenResponse>
At you moment all you are doing is testing a multiRef element exists, and outputting only one new getGenReturn element.
All you really need to do is replace the xsl:if with xsl:for-each to select all the elements, then you will get one getGenReturn for each. And also change the xsl:value-of to use a relative path
<xsl:template match="/">
<xsl:element name="getGenResponse">
<xsl:for-each select="//soap:Body/multiRef">
<xsl:element name="getGenReturn">
<xsl:element name="name"><xsl:value-of select="name"/></xsl:element>
<xsl:element name="mail"><xsl:value-of select="mail"/></xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
Or better still, do this, as xsl:element is not really needed here if you are using static names
<xsl:template match="/">
<getGenResponse>
<xsl:for-each select="//soap:Body/multiRef">
<getGenReturn>
<name><xsl:value-of select="name"/></name>
<mail><xsl:value-of select="mail"/></mail>
</getGenReturn>
</xsl:for-each>
</getGenResponse>
</xsl:template>
Note, you don't actually need the identity template in this case. Try this XSLT:
<xsl:stylesheet version="1.0" xmlns:response="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="soap response">
<!-- Output -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<getGenResponse>
<xsl:for-each select="//soap:Body/multiRef">
<getGenReturn>
<name><xsl:value-of select="name"/></name>
<mail><xsl:value-of select="mail"/></mail>
</getGenReturn>
</xsl:for-each>
</getGenResponse>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:response="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="soap response">
<!-- Output -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<getGenResponse>
<xsl:for-each select="//soap:Body/multiRef">
<getGenReturn>
<name><xsl:value-of select="name"/></name>
<mail><xsl:value-of select="mail"/></mail>
</getGenReturn>
</xsl:for-each>
</getGenResponse>
</xsl:template>
</xsl:stylesheet>
I have some XML and having a difficult time transforming it.
Example XML:
<?xml version="1.0" encoding="utf-8"?>
<Cars xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Car> ... </Car>
</Cars>
I would like to change it to:
<?xml version="1.0" encoding="utf-8"?>
<Depot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Cars>
<Car> ... </Car>
</Cars>
</Depot>
Sounds simple enough but the problem is some data is already in the expected format, in which case I don't want to apply the transform. How do I achieve this?
EDIT
Some starting XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" mlns:xsi="http://www.w3.org/2001/XMLSchema-
instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Cars">
<Depot>
<Cars>
<xsl:apply-templates select="*"/>
</Cars>
</Depot>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I think you only want to match Cars if it is the root element, so instead of your template matching "Cars", change it to match "/Cars"
<xsl:template match="/Cars">
Try this XSLT (which I have slightly amended to get the first template to call the identity template)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<xsl:output method="xml" indent="yes" />
<xsl:template match="/Cars">
<Depot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:call-template name="identity" />
</Depot>
</xsl:template>
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I think that it is just necessary to use a choose in the root template to test if the node Depot exists, if not create it:
<xsl:template match="/">
<xsl:choose>
<xsl:when test="Depot">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
<Depot>
<xsl:apply-templates/>
</Depot>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
This also gives same output.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<xsl:template match="Cars">
<Depot>
<xsl:copy-of select="."/>
</Depot>
</xsl:template>
</xsl:stylesheet>
I am newbie to XSLT.can you help me for xslt to achieve below output. In my input xml have duplicate nodes and i have to remove based on element (CustAccId) value should not be re-peat.
Inputxml :
<Main>
<Request>
<TypeInd>I</TypeInd>
<CustAcctID>505665599</CustAcctID>
<ServiceOrderID>1452653</ServiceOrderID>
</Request>
<Request>
<TypeInd>O</TypeInd>
<CustAcctID>2011395</CustAcctID>
<ServiceOrderID>1452652</ServiceOrderID>
</Request>
<Request>
<TypeInd>I</TypeInd>
<CustAcctID>505665599</CustAcctID>
<ServiceOrderID>1452653</ServiceOrderID>
</Request>
</Main>
Output XML :
<Main>
<Request>
<TypeInd>I</TypeInd>
<CustAcctID>505665599</CustAcctID>
<ServiceOrderID>1452653</ServiceOrderID>
</Request>
<Request>
<TypeInd>O</TypeInd>
<CustAcctID>2011395</CustAcctID>
<ServiceOrderID>1452652</ServiceOrderID>
</Request>
Here is XSLt i tried but didn't work like it retrun duplicate request node
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:if test="not(following::Request[CustAcctID=current()])">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
You can remove the duplicate with following XSLT:
<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="Request[CustAcctID = following::Request/CustAcctID]"/>
</xsl:stylesheet>
Output XML:
<?xml version="1.0" encoding="UTF-8"?>
<Main>
<Request>
<TypeInd>O</TypeInd>
<CustAcctID>2011395</CustAcctID>
<ServiceOrderID>1452652</ServiceOrderID>
</Request>
<Request>
<TypeInd>I</TypeInd>
<CustAcctID>505665599</CustAcctID>
<ServiceOrderID>1452653</ServiceOrderID>
</Request>
</Main>
The template matching all Request nodes where the CustAcctID matches the CustAcctID of the following Request will not produce any output for the matching Request, so the duplicates will not be written.
Update for the advice in the comment by michael.hor257k: Another approach is to use Muenchian grouping:
<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:key name="x" match="ServiceOrderID" use="." />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Request">
<xsl:for-each select=".">
<xsl:if test="generate-id(ServiceOrderID) =
generate-id(key('x', ServiceOrderID)[1])">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
which produces the same output XML but can be more efficient as you'll find described in detail in the article by Jeni Tennison http://www.jenitennison.com/xslt/grouping/muenchian.xml that michael.hor257k already recommended.
As additional reference for XSLT grouping you can have a look at http://www.dpawson.co.uk/xsl/sect2/N4486.html
i'm stucked. Please help me with a little problem.
I have to change just two specific lines in XML file like this:
<?xml version="1.0" encoding="UTF-8"?>
<max:PublishTP_WORKORDER xmlns:max="http://www.ibm.com/maximo" creationDateTime="2014-04-11T10:43:51+04:00" transLanguage="RU" baseLanguage="EN" messageID="1397198631936413520" maximoVersion="7 5 20130829-1209 V7510--1" event="1">
<TP_WORKORDERSet xmlns="http://www.ibm.com/maximo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<WORKORDER action="Replace">
<ACTCOST xsi:nil="true"/>
<ACTFINISH xsi:nil="true"/>
<ACTINTLABCOST>0.0</ACTINTLABCOST>
<ACTINTLABHRS>0.0</ACTINTLABHRS>
<ACTLABCOST>0.0</ACTLABCOST>
<ACTLABHRS>0.0</ACTLABHRS>
<ACTMATCOST>0.0</ACTMATCOST>
<ACTOUTLABCOST>0.0</ACTOUTLABCOST>
<ACTOUTLABHRS>0.0</ACTOUTLABHRS>
<ACTSERVCOST>0.0</ACTSERVCOST>
<ACTSTART>2013-11-08T12:03:26+04:00</ACTSTART>
<ACTTOOLCOST>0.0</ACTTOOLCOST>
<ADDRESS/>
<AMCREW/>
<AMS>0</AMS>
<AOS>0</AOS>
...........................
<WORKORDERID>10</WORKORDERID>
<WORKPACKMTLSTATUS/>
<WORKTYPE/>
<WOSEQUENCE xsi:nil="true"/>
</WORKORDER>
</TP_WORKORDERSet>
</max:PublishTP_WORKORDER>
I need to replace "PublishTP_WORKORDER" with "Create_WORKORDER", both open and close tags.
It works fine with:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:max="http://www.ibm.com/maximo" version="1.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/max:PublishTP_WORKORDER">
<xsl:element name="max:CreateTP_WORKORDER">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
But in XML file it could be "PublishTP_WORKORDER2" or "PublishTP_WORKORDER3" and so on.
It should be changed to "CreateTP_WORKORDER2", "CreateTP_WORKORDER3" etc
And this XSLT scheme stops working. It's just doesn't recognize strings with added numeric symbols. How could i turn it out? Thanks in advance.
It's always root element
Then how about:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:max="http://www.ibm.com/maximo">
<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="/*">
<xsl:variable name="suffix" select="substring-after(local-name(), 'PublishTP_WORKORDER')" />
<xsl:element name="max:CreateTP_WORKORDER{$suffix}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
I have several XML files, as follows:
file : 1.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<config>
<info>
<info1>val1</info1>
<info2>val2</info2>
</info>
<info>
<info1>val3</info1>
<info2>val4</info2>
</info>
</config>
file : 2.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<config>
<info>
<info1>val5</info1>
<info2>val6</info2>
</info>
<info>
<info1>val7</info1>
<info2>val8</info2>
</info>
</config>
file: 3.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<config>
<info>
<info1>val9</info1>
<info2>val10</info2>
</info>
<info>
<info1>val11</info1>
<info2>val12</info2>
</info>
</config>
using XSLT2.0 (saxon), I would like to merge them and also add to each node:
<info3>XXX</info3>
and also
<file>filename.xml</file>
filename.xml was the file from which the info has been copied.
The output should look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<config>
<info>
<info1>val1</info1>
<info2>val2</info2>
<info3>XXX</info3>
<file>1.xml</file>
</info>
<info>
<info1>val3</info1>
<info2>val4</info2>
<info3>XXX</info3>
<file>1.xml</file>
</info>
<info>
<info1>val5</info1>
<info2>val6</info2>
<info3>XXX</info3>
<file>2.xml</file>
</info>
<info>
<info1>val7</info1>
<info2>val8</info2>
<info3>XXX</info3>
<file>2.xml</file>
</info>
<info>
<info1>val9</info1>
<info2>val10</info2>
<info3>XXX</info3>
<file>3.xml</file>
</info>
<info>
<info1>val11</info1>
<info2>val12</info2>
<info3>XXX</info3>
<file>3.xml</file>
</info>
</config>
So far I have been able to merge the file by creating an XML file that lists the file I want to merge (merge.xml):
<mergeData newRoot="config">
<filelist>
<fileItem>1.xml</fileItem>
<fileItem>2.xml</fileItem>
<fileItem>3.xml</fileItem>
</filelist>
</mergeData>
using the following XSL (merge.xsl):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="#all">
<xsl:param name="new">
<info>XXX</info>
</xsl:param>
<xsl:template match="/">
<xsl:element name="{mergeData/#newRoot}">
<xsl:apply-templates select="mergeData/fileList/fileItem"/>
</xsl:element>
</xsl:template>
<xsl:template match="fileItem">
<xsl:apply-templates select="document(translate(., '\', '/'))/config/*"/>
</xsl:template>
<xsl:template match="config/*">
<xsl:copy>
<xsl:copy-of select="node()"/>
<xsl:copy-of select="$new"/>
</xsl:copy>
<file><xsl:value-of select="tokenize(document-uri(.), '/')[last()]"/></file>
</xsl:template>
How should I modify the XSL to get the filename into each info at the same time.
Really the only thing you should have to do is move file inside of the xsl:copy.
Example (with a couple of other minor mods):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:param name="new">
<info3>XXX</info3>
</xsl:param>
<xsl:template match="/">
<xsl:element name="{mergeData/#newRoot}">
<xsl:apply-templates select="mergeData/filelist/fileItem"/>
</xsl:element>
</xsl:template>
<xsl:template match="fileItem">
<xsl:apply-templates select="document(translate(., '\', '/'))/config/*"/>
</xsl:template>
<xsl:template match="config/*">
<xsl:copy>
<xsl:copy-of select="node(),$new"/>
<file><xsl:value-of select="tokenize(document-uri(/), '/')[last()]"/></file>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You could also do this using collection() instead of creating the separate mergeData.xml file:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="newRoot" select="'config'"/>
<xsl:param name="new">
<info3>XXX</info3>
</xsl:param>
<xsl:template match="/">
<xsl:element name="{$newRoot}">
<xsl:apply-templates select="collection('file:///C:/some/path?select=[0-9]*.xml')/*/info"/>
</xsl:element>
</xsl:template>
<xsl:template match="info">
<xsl:copy>
<xsl:copy-of select="#*|node(),$new"/>
<file><xsl:value-of select="tokenize(document-uri(/),'/')[last()]"/></file>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
One additional alternative, since you're using Saxon, is to use saxon:discard-document() along with your mergeData.xml input. If you have a lot of files listed in mergeData.xml, this can help with memory consumption. (It does require Saxon PE or EE or an older version of Saxon that allows the extension functions.)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="new">
<info3>XXX</info3>
</xsl:param>
<xsl:template match="/mergeData">
<xsl:element name="{#newRoot}">
<xsl:apply-templates select="filelist/fileItem"/>
</xsl:element>
</xsl:template>
<xsl:template match="fileItem">
<xsl:apply-templates select="document(.)/saxon:discard-document(.)/*/*" xmlns:saxon="http://saxon.sf.net/"/>
</xsl:template>
<xsl:template match="info">
<xsl:copy>
<xsl:copy-of select="#*|node(),$new"/>
<file><xsl:value-of select="tokenize(document-uri(/),'/')[last()]"/></file>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The following XSLT yields your required result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:param name="new">
<info>XXX</info>
</xsl:param>
<xsl:template match="/mergeData">
<config>
<xsl:for-each select="filelist/fileItem">
<xsl:variable name="filename" select="text()"/>
<xsl:for-each select="document($filename)/config/info">
<info>
<xsl:copy-of select="./*"/>
<xsl:element name="info{count(*)+1}">
<xsl:value-of select="$new"/>
</xsl:element>
<file><xsl:value-of select="$filename"/></file>
</info>
</xsl:for-each>
</xsl:for-each>
</config>
</xsl:template>
</xsl:stylesheet>
Notes:
This already works with XSLT 1.0, hence I changed the XSLT declaration.
Since this approach is top down with a predefined sub structure it does not use the attribute newRoot of your input file anymore.
The answer does not extract the basename of your input files but uses the full path supplied in the merge configuration. You may want to revert this simplification. Of course, using tokenize pushes it back to XSLT 2.0 or extended functions.