Search code examples
c#xmlxsltxslcompiledtransform

Pass multiple xml files into XSLT transform C#


I am trying to convert the following xslt to reference an in-memory 'audio' xml file instead of the physical audio.xml file. The following xslt file works with the physical xml files.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom-functions">
    <xsl:output method="xml" indent="yes" version="1.0" encoding="ISO-8859-1"/>

    <xsl:param name="audioxml" select="'./audio.xml'"/>

    <xsl:variable name="audiofile" select="document($audioxml)"/>

    <xsl:template match="/">
        <xsl:for-each select="bookstore" >
            <xsl:for-each select="book" >
                <booktitle>
                    <xsl:value-of select="title" />
                </booktitle>
            </xsl:for-each>
        </xsl:for-each>

        <xsl:for-each select="$audiofile">
            <xsl:for-each select="audiostore" >
                <xsl:for-each select="audio" >
                    <audiotitle>
                        <xsl:value-of select="title" />
                    </audiotitle>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

book.xml

<?xml version=\"1.0\" encoding=\"utf-8\" ?><bookstore><book genre=\"autobiography\" publicationdate=\"1981\" ISBN=\"1-861003-11-0\"><title>The Autobiography of Benjamin Franklin</title><author><first-name>Benjamin</first-name><last-name>Franklin</last-name></author><price>8.99</price></book></bookstore>

audio.xml

<?xml version=\"1.0\" encoding=\"utf-8\" ?><audiostore><audio genre=\"autobiography\" publicationdate=\"1981\" ISBN=\"1-861003-11-0\"><title>The Autobiography of Benjamin Franklin 2</title><author><first-name>Benjamin 2</first-name><last-name>Franklin 2</last-name></author><price>8.99</price></audio></audiostore>

So I am trying to pass the xml files in-memory but the following code is complaining that An error occurred while loading document '/file2.xml'

public static string MergeXml(string xml1, string xml2) {
    XslCompiledTransform xslt = new XslCompiledTransform();
    XmlDocument xsltDoc = new XmlDocument();
    // Load the XSLT file through XmlReader to override the base URI.
    using (StreamReader reader = File.OpenText(@"template.xsl"))
    using (XmlReader xmlReader = XmlReader.Create(reader, null, "file:///template.xsl"))
    {
        xsltDoc.Load(xmlReader);
    }
    // Use XsltSettings to enable the use of the document() function.
    xslt.Load(xsltDoc, new XsltSettings(true, false), null);

    // Load the first XML file into a document
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml1);

    // Create the resolver and add the second file to it.
    XmlPreloadedResolver resolver = new XmlPreloadedResolver();
    resolver.Add(new Uri("file:///file2.xml"), xml2);

    using (StringWriter writer = new StringWriter())
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        // Pass the resolver to the transform
        xslt.Transform(doc, null, xmlWriter, resolver);
        return writer.ToString();
    }
}

Solution

  • It seems, the Add method of the XmlPreloadedResolver, when taking a string, parses it as UTF-16/Encoding.Unicode in .NET so either don't put any XML declaration on the strings you pass to the Add method or make sure they declare UTF-16 e.g. var xml2 = "<?xml version=\"1.0\" encoding=\"utf-16\" ?><audiostore>...