I am trying to extract a single node from some XML and write the node and all of its child contents to a new XML document and save it to disk. In some cases (such as my test case) there are multiple Nodes that suit the criteria, and all of them must be written to separate files.

So far everything in my function works as intended, right up until I go to write the file to disk. The exception thrown is: "Exception thrown: 'System.Xml.XmlException' in System.Xml.dll" and the message attached is "Invalid XML document. The document does not have a root element." How do I resolve this?

I've added a lot of console outs to show that each stage is working as expected. My function is as follows:

private void ExtractQIF()
        {
            var httpClient = new HttpClient();
            int QIFFound = 0;
            try
            {
                string assetsTarget = httpAuthority + "/asset";                
                var XMLRaw = httpClient.GetStringAsync(assetsTarget);
                XmlDocument XML = new XmlDocument();
                XML.LoadXml(XMLRaw.Result);                                             
                XmlNodeList QIFDocuments = XML.GetElementsByTagName("QIFDocument"); 
                Console.WriteLine("QIF Documents found: " + QIFDocuments.Count);        // WE ARE SUCCESSFULLY FINDING QIFDOCS IN THE ASSETS REQ
                foreach (XmlNode QIFDoc in QIFDocuments)
                {
                    QIFFound++;
                    try
                    {
                        Console.WriteLine(QIFDoc.InnerXml); // Debug shizzle
                        Console.WriteLine($"Document #{QIFFound} is being saved");
                        XmlDocument OutputQIFFile = new XmlDocument();
                        OutputQIFFile.ImportNode(QIFDoc, true);
                        Console.WriteLine("Node Imported to Document"); // Debug Shizzle
                        OutputQIFFile.Save(QIFSaveLocation); // This is the bastard line that isn't working
                        Console.WriteLine($"Document {QIFFound} Saved to Disk"); // Debug Shizzle
                        //Finally we should change the file extension to .qif
                    }
                    catch (Exception balls)
                    {
                        Console.WriteLine("COULD NOT EXTRACT QIF: Failed at document " + QIFFound);
                        Console.WriteLine(balls.Message);
                    }

                }
                Console.WriteLine("All QIF written to disk");                
            }
            catch
            { MessageBox.Show("COULD NOT EXTRACT ALL QIF");}

        }

The relevant console information is as follows:

QIF Documents found: 2
<QPId xmlns="http://qifstandards.org/xsd/qif3">ec871a54-5bb5-470b-9ff7-de757d7726a1</QPId><Version xmlns="http://qifstandards.org/xsd/qif3"><TimeCreated>2019-01-22T15:51:20.874+00:00</TimeCreated></Version><Header xmlns="http://qifstandards.org/xsd/qif3">.... Blah Blah Blah, a shit tonne of XML
Document #1 is being saved
Node Imported to Document
Exception thrown: 'System.Xml.XmlException' in System.Xml.dll
COULD NOT EXTRACT QIF: Failed at document 1
Invalid XML document. The document does not have a root element.
<QPId xmlns="http://qifstandards.org/xsd/qif3">27400291-ea3d-41de-afee-69d186c4288f</QPId><Version xmlns="http://qifstandards.org/xsd/qif3"><TimeCreated>2019-01-22T15:50:16.827+00:00</TimeCreated></Version><Header xmlns="http://qifstandards.org/xsd/qif3"><Application> .... Blah Blah Bla, a shit tonne of XML
Document #2 is being saved
Node Imported to Document
Exception thrown: 'System.Xml.XmlException' in System.Xml.dll
COULD NOT EXTRACT QIF: Failed at document 2
Invalid XML document. The document does not have a root element.
All QIF written to disk

I've also tried appending the node to the document itself but the errors and advice around them seem to lead me back to how I am trying to implement it above.

Looks to me like the node is correctly populated. Any ideas?

1

There are 1 best solutions below

2
On

Per the docs, ImportNode only makes a copy of the specified node and returns it, it doesn't actually insert it into the document. You can see the node needs to be added in the example given.

So to make this work, you'd need to do change to do the following:

var outputQIFFile = new XmlDocument();

var newQifNode = outputQIFFile.ImportNode(QIFDoc, true);

outputQIFFile.AppendChild(newQifNode);

outputQIFFile.Save(QIFSaveLocation);

However, as suggested in the comments I would strongly suggest you look at LINQ to XML (XDocument and friends). This is a much more modern and user friendly API.