Search code examples
c#xsltxmlreader

transform xml-file depending on root-tag


I have an xml-file which I want to read. Depending on the root-tag I´m doing an xsl-transform before and read the modified file:

XmlReader reader = XmlReader.Create(myFile);

var root = new XmlDocument();
root.Load(reader);
if (root.DocumentElement.Name == "FC_FeatureCatalogue")
{
    var xsltDoc = new XmlDocument();
    xsltDoc.Load("myXslt.xsl"));

    XsltSettings xsltSettings = new XsltSettings(false, true);
    var transformer = new XslCompiledTransform();
    transformer.Load(xsltDoc, xsltSettings, new XmlUrlResolver());

    using (var stream = new FileStream(newFileName, FileMode.Create))
    {
        transformer.Transform(reader, new XsltArgumentList(), stream);
    }
}

When the condition passes the file determined by newFileName is created. However it does contain only an empty entry. So I debugged a bit and noticed that when calling root.Load(reader) the file is read until EOF. This is why I assume when using the same file for the transformation the transformer simply does nothing as the reader has no further content.

So is there a way to re-set the reader (I know, XmlReader is ment to be "forward only") or alternativly get the root-tag of the original xml-file without reading to EOF and transform it?

EDIT: To verify my assumption I also added these lines within my using-block:

using (var stream = new FileStream(newFileName, FileMode.Create))
{
    reader.Close();
    reader = XmlReader.Create(myFile);
    transformer.Transform(reader, new XsltArgumentList(), stream);
}

Now the created file contains all the expected data. However I hope there´ll be a way to read the root-tag and transform the file without re-reding the whole file.


Solution

  • I found an approach that was inspired here. Actually I won´t need to read the entire document (as XmlDocument.Load does) to only get the root-element. So I simply read the readers first lines:

    while (reader.Read()) 
    {
        if (reader.NodeType == XmlNodeType.Element) break;
    }
    if (reader.Name == "FC_FeatureCatalogue")
    {
        // ...
    }
    

    Alternativly you may also use this as suggested by jdweng which is a bit shorter:

    reader.MoveToContent();
    if (reader.NodeType == XmlNodeType.Element) { ... }
    

    Supprisingly to me is only that although the readers internal position is now somewhere within the document we can transform the xml appropriately. I guess this is because the elements read before are just "xml-chunk" like the xml-declaration or any comments.