0

I have problem parse XML in C# because XML not have root element. How can I add root element? When try XDocument show erorrs about root element. Maybe can use some file stream?

Example:

<data>
  <datetime>29.06.2020 10:15:15</datetime>
  <Lenght/>
  <Width>3</Width>
  <Height>2</Height>
</data>
<data>
  <datetime>29.06.2020 10:15:01</datetime>
  <Lenght>1</Lenght>
  <Width>2</Width>
  <Height>3</Height>
</data>

My code:

XmlDocument report = new XmlDocument();
report.Load(fileOfReport);                   //there show error about root element
XmlElement root = report.CreateElement("root");           
var items = report.GetElementsByTagName("data");
for (int i = 0; i < items.Count; i++)
{
    root.AppendChild(items[i]);
}
report.AppendChild(root);
report.SaveAs(fileOfReport);
7
  • 1
    Basically, what you have isn't an XML document. The simplest option would be to add a root element to it - just put <root> at the start and </root> at the end, potentially in the file itself as a pre-processing step. Commented Jul 1, 2020 at 11:19
  • I need to program add these root elements, because, the program which generates this XML add new rows after my root element. Example: <root> <data></data></root><data></data> Commented Jul 1, 2020 at 11:22
  • 1
    Are you able to modify the program that generates the XML to start with? If that could be changed to output valid XML documents, that would be the ideal solution. (I'd also strongly advise using LINQ to XML instead of the old XmlDocument-based API. It's a much simpler API to use.) Commented Jul 1, 2020 at 11:24
  • I can't edit this program, do not have source code for that. Can LINQ solve my problem with nonvalid XML? Commented Jul 1, 2020 at 11:27
  • 1
    No, and you basically shouldn't try IMO. I would suggest writing a tiny program that just adds the root element start/end, but in a different file - so any time the original file is updated (with more elements) you just rewrite your modified file, and you get a valid XML document. I suspect you could read just one XML element at a time, but it's likely to be easier if you have a valid XML document to start with. Commented Jul 1, 2020 at 11:31

1 Answer 1

2

You can try the following solution.

Lots of minutiae string handling, but seems to be working for your case. XmlNodeType enumerator has 18 entries total. Your XML is relatively simple, that's why the switch has just 3 node types in the code. You can use StringBuilder instead of string data type while composing a well-formed XML.

void Main()
{
    const string FILENAME = @"e:\temp\NoRootFile.xml";
    const string NEWFILENAME = @"e:\temp\NoRootFileFixed.xml";
    string xmlString = "<root>";

    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ConformanceLevel = ConformanceLevel.Fragment;

    using (XmlReader xr = XmlReader.Create(FILENAME, settings))
    {
        while (xr.Read())
        {
            if (xr.NodeType != XmlNodeType.XmlDeclaration)
            {
                switch (xr.NodeType)
                {
                    case XmlNodeType.Element:
                        xmlString += "<" + xr.Name + ((xr.IsEmptyElement) ? "/>" : ">");
                        break;
                    case XmlNodeType.Text:
                        xmlString += xr.Value;
                        break;
                    case XmlNodeType.EndElement:
                        xmlString += "</" + xr.Name + ">";
                        break;
                }
            }
        }
    }
    xmlString += "</root>";

    XDocument xdoc = XDocument.Parse(xmlString);
    xdoc.Save(NEWFILENAME);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.