C# – Add to the top of a xml file after xsl transform

c++excelxmlxslt

I have successfully been able to transform a simple xml file with data to another xml file (excel template) using a xsl template, this is what my xsl file looks like:

<?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" standalone="yes"/>

    <xsl:template match="/">
      <xsl:processing-instruction name="mso-application">
        <xsl:text>progid="Excel.Sheet"</xsl:text>
      </xsl:processing-instruction>
    ...(stuff here)...
    </xsl:template>
  </xsl:stylesheet>

The resulting xml file is written out correctly BUT with the exception of including

<?xml version="1.0"?>

at the top of the file. How can I get it to appear at the top?

Currently my resulting xml file starts with:

<?mso-application progid="Excel.Sheet"?>
...(rest of file)...

But what I need it to do is:

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
.(rest of file)...

I'm doing this transform through a windows form with the following code:

XPathDocument myXPathDoc = new XPathDocument(xmlfile);
XslCompiledTransform myXslTrans = new XslCompiledTransform();
myXslTrans.Load(xslfile);
XmlTextWriter myWriter = new XmlTextWriter(xmlexcelfile, null);
myWriter.Formatting = Formatting.Indented;
myWriter.Namespaces = true;
myXslTrans.Transform(myXPathDoc, null, myWriter);
myWriter.Close();

I've tried playing around with the xsl:output standalone="yes/no", as well as omit-xml-declaration="no". I've also tried (in the C#) code adding myWriter.WriteStartDocument(); before transforming but that was not allowed. I have tried searching online for this as well and keep coming back to the standalone="yes" but that isn't working. Is there something I am missing here? Oh and in case you are wondering why I need to have the

<?xml version="1.0"?>

at the top of the resulting file, it's because when opening the xml file with excel, excel doesn't recognize it correctly but if it is included then excel opens it correctly…

Best Solution

You can do this

<xsl:output method="xml" indent="yes" omit-xml-declaration="no" />

or something similar to this using XmlWriterSettings

Edit: Added more code. Previous was missing some parts

        XmlWriterSettings writerSettings = null;
        XsltArgumentList transformationArguments = null;
        XslCompiledTransform transformer = null;
        MemoryStream memoryStream = null;
        XPathDocument xPathDocument = null;
        StringBuilder sb = null;
        XmlWriter writer = null;
        XmlDocument resultXml = null;
        try
        {
            writerSettings = new XmlWriterSettings();
            writerSettings.OmitXmlDeclaration = false; // This does it
            writerSettings.Indent = true;

            transformationArguments = new XsltArgumentList();
            transformer = new XslCompiledTransform();
            memoryStream = new MemoryStream(System.Text.Encoding.Default.GetBytes(xml.OuterXml));
            xPathDocument = new XPathDocument(new StreamReader(memoryStream));
            sb = new StringBuilder();
            // give the settings to the writer here
            writer = XmlWriter.Create(sb, writerSettings);
            // this is not mandatory, obviously, just passing parameters to my xslt file
            foreach (KeyValuePair<string, object> parameter in parameters)
            {
                transformationArguments.AddParam(parameter.Key, string.Empty, parameter.Value);
            }

            using (Stream strm = Assembly.GetExecutingAssembly().GetManifestResourceStream("Lib.XSLTFile1.xslt"))
            using (XmlReader reader = XmlReader.Create(strm))
            {
                transformer.Load(reader);
                transformer.Transform(xPathDocument, transformationArguments, writer);
            }
            resultXml = new XmlDocument();
            resultXml.LoadXml(sb.ToString());
            // for testing only
            File.AppendAllText(@"Your path goes here\result.xml", resultXml.OuterXml);
        }
        catch (Exception)
        {
            throw;
        }

This is how I do it, but this code is specifically written to create an instance of a XmlDocument. I'm sure you can adapt to your needs.

Related Question