Reputation: 115
I have the following xml:
<PCstore>
<StoreList>
<Store id="001">
<ItemList>
<Items laptop="DELL" price="300"/>
<Items laptop="gateway" price="450"/>
<Items screen="LG" price="200"/>
</ItemList>
</Store>
</StoreList>
</PCstore>
I have to merge with:
<PCstore>
<StoreList>
<Store id="002">
<ItemList>
<Items laptop="gateway" price="650"/>
<Items screen="LG" price="200/>
<Items speakers="sony" price="50"/>
</ItemList>
</Store>
</StoreList>
</PCstore>
And the desire output ifiltering the attribute (laptop="gateway"):
<PCstore>
<StoreList>
<Store id="001">
<ItemList>
<Items laptop="gateway" price="450"/>
</ItemList>
</Store>
<Store id="002">
<ItemList>
<Items laptop="gateway" price="650"/>
</ItemList>
</Store>
</StoreList>
</PCstore>
And so on for more xml3.xml, xml4.xml etc...
I don't have the codes I tried, I'm kinda new on XSLT, i hope someone can assist me with this.
UPDATE:
I tried this code, but its not working...
<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:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Items">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
<xsl:apply-templates
select="document('xml2.xml')
/PCstore/StoreList/Store/ItemList[@id = current()/../@id]
/Items[@laptop = current()/@value]/*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 179
Reputation: 70638
If you can only use XSLT1.0, one way to do this would be to pass the list of xml files as a parameter to your XSLT. For example:
<xsl:param name="filelist">
<files>
<file>xml2.xml</file>
<!-- We can place here xml3.xml and so on -->
</files>
</xsl:param>
(So, in this case, I am assuming you apply the XSLT to the first xml1.xml, and you only pass in any other files as parameters).
However, in XSLT1.0 you will need to make use of an extension function to process this parameter as a node-set. Doing <xsl:for-each select="$filelist/files/file">
will result in the error "Reference to variable or parameter 'files' must evaluate to a node list.". Therefore you will need to use an extension function to convert it into a node-set. In my example, I will be using Microsoft's one in my example, but depending on your platform, you might use exslt.org/common
Here is the full XSLT in this case
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
extension-element-prefixes="msxml">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="filelist">
<files>
<file>xml2.xml</file>
</files>
</xsl:param>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="StoreList">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:for-each select="msxml:node-set($filelist)/files/file">
<xsl:apply-templates select="document(text())/PCstore/StoreList/Store"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="Items[not(@laptop='gateway')]"/>
</xsl:stylesheet>
When applied to your XSLT the following it output
<PCstore>
<StoreList>
<Store id="001">
<ItemList>
<Items laptop="gateway" price="450"/>
</ItemList>
</Store>
<Store id="002">
<ItemList>
<Items laptop="gateway" price="650"/>
</ItemList>
</Store>
</StoreList>
</PCstore>
Do note, the files must exist for this to work. If you pass in the name of a file that does not exist, an error will occur.
Upvotes: 1
Reputation: 52878
If you can use XSLT 2.0, you can use collection()
...
xml1.xml
<PCstore>
<StoreList>
<Store id="001">
<ItemList>
<Items laptop="DELL" price="300"/>
<Items laptop="gateway" price="450"/>
<Items screen="LG" price="200"/>
</ItemList>
</Store>
</StoreList>
</PCstore>
xml2.xml
<PCstore>
<StoreList>
<Store id="002">
<ItemList>
<Items laptop="gateway" price="650"/>
<Items screen="LG" price="200"/>
<Items speakers="sony" price="50"/>
</ItemList>
</Store>
</StoreList>
</PCstore>
XSLT 2.0
<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="type" select="'laptop'"/>
<xsl:param name="brand" select="'gateway'"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<PCstore>
<StoreList>
<xsl:apply-templates select="collection('file:///C:/store_test?select=*.xml')/PCstore/StoreList/Store"/>
</StoreList>
</PCstore>
</xsl:template>
<xsl:template match="Items[not(@*[name()=$type]=$brand)]"/>
</xsl:stylesheet>
Output
<PCstore>
<StoreList>
<Store id="001">
<ItemList>
<Items laptop="gateway" price="450"/>
</ItemList>
</Store>
<Store id="002">
<ItemList>
<Items laptop="gateway" price="650"/>
</ItemList>
</Store>
</StoreList>
</PCstore>
Upvotes: 0