Reputation: 3924
I have a requirement to merge multiple xml files in to a single file. I achieved this by xsl transform. My xslt file is
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl"
xmlns:Utils="Utils:Helper">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="assemblies">
<xsl:copy>
<xsl:apply-templates select="*"/>
<xsl:apply-templates select="document('AdminService.xml')/reflection/assemblies/*" />
<xsl:apply-templates select="document('Helpers.xml')/reflection/assemblies/*" />
<!--<xsl:value-of select="Utils:GetFiles()"/>-->
</xsl:copy>
</xsl:template>
<xsl:template match="apis">
<xsl:copy>
<xsl:apply-templates select="*"/>
<xsl:apply-templates select="document('AdminService.xml')/reflection/apis/*" />
<xsl:apply-templates select="document('Helpers.xml')/reflection/assemblies/*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
My C# function is
var xslt = new XslCompiledTransform();
xslt.Load("XmlMerger.xslt", new XsltSettings { EnableDocumentFunction = true, EnableScript = true}, null);
using (var writer = File.CreateText("XmlDocs\\result.xml"))
{
xslt.Transform(@"EmployeeService.xml", arguments, writer);
}
In this three xml files EmployeeService, AdminService, Helpers are merged into a single file results.xml. This is working fine for me.
Now the calling of the xml files is static
<xsl:apply-templates select="document('AdminService.xml')/reflection/assemblies/*" />
<xsl:apply-templates select="document('Helpers.xml')/reflection/assemblies/*" />.
I need to include all the xml files in a directory. Currently i tried by calling C# function in this xslt file by passing string like
public string GetFiles()
{
return "<xsl:apply-templates select=\"document(\'Helpers.xml\')/reflection/assemblies/*\" />";
//return "Helpers.xml";
}
Note: Just for example i included only one file. Here I am trying to build that string pass it to the xslt file
<xsl:value-of select="Utils:GetFiles()"/>
But in the results its coming as plain text. How to escape this and tell its a template or how to dynamically include all the files from a directory ?
Upvotes: 1
Views: 1226
Reputation: 167696
If you want to process an XML document in XSLT with XslCompiledTransform
then you need to pass in an XPathNavigator
from your C# code, if you want to process a directory of XML documents then you need to pass in an array of XPathNavigator
objects. So you can write a method
public XPathNavigator[] GetDocuments(string directory)
{
return Directory.EnumerateFiles(directory, "*.xml").Select(file => new XPathDocument(file).CreateNavigator()).ToArray();
}
in a sample class MyHelperClass
, instantiate that class in your C# code and pass it as an extension to the Transform
call:
XslCompiledTransform xsltProc = new XslCompiledTransform();
xsltProc.Load("XSLTFile1.xslt");
XsltArgumentList xsltArgs = new XsltArgumentList();
xsltArgs.AddExtensionObject("http://example.com/mf", new MyHelperClass());
xsltProc.Transform("input.xml", xsltArgs, Console.Out);
Then in your XSLT use e.g.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="msxsl mf"
>
and then you can process e.g.
<xsl:apply-templates select="mf:GetDocuments('someDirectoryName')/root/foo/bar"/>
to process all bar
elements found in the XML documents in the directory.
Upvotes: 2