0

I am trying to convert XML files (which contents/structure i dont know) into a custom tree. The tree has a constructor of the following form:

InformationNode(String key, String value, 'enum' type).

The InformationNode has a addChild function, there is no limit of the amount of children. My current code is as follows:

public static InformationNode fromXML(String xml)
    {
        xml = xml.Replace("< ", "<").Replace("</ ", "</"); //Bugfix for some API's.
        XDocument xdoc = XDocument.Parse(xml);
        var details = xdoc.Root.Elements();
        String key = "->";

        InformationNode node = new InformationNode(key, "", InformationType.Object);
        foreach (var detail in details)
        {
            //If XML is Leaf.
            if (details.Count() == 0 && int.TryParse(detail.Value.Trim().ToString(), out var n))
                 return new InformationNode(key, detail.Value.Trim().ToString(), InformationType.Int);
            if (details.Count() == 0)
                 return new InformationNode(key, detail.Value.Trim().ToString(), InformationType.String);
            //If XML is object:
            node.addChild(fromXML(detail.Value.Trim()));                
        }
        return node;
    }

but unfortunately an empty node is returned. Can anyone tell me what i do wrong?

Edit: as per request: 2 test cases.

InformationNode a = InformationNode.fromXML("<stationcode> 6391 </ stationcode >"); 
InformationNode b =  InformationNode.fromXML("<?xml version=\"1.0\" encoding=\"utf - 8\" ?><weerstation id=\"6391\"><stationcode> 6391 </ stationcode >< stationnaam regio = \"Venlo\" > Meetstation Arcen </ stationnaam >< lat > 51.50 </ lat >< lon > 6.20 </ lon >< datum > 09 / 28 / 2017 20:20:00 </ datum >< luchtvochtigheid > 80 </ luchtvochtigheid >< temperatuurGC > 18.7 </ temperatuurGC >< windsnelheidMS > 3.5 </ windsnelheidMS >< windsnelheidBF > 3 </ windsnelheidBF >< windrichtingGR > 207 </ windrichtingGR >< windrichting > ZZW </ windrichting >< luchtdruk > -</ luchtdruk >< zichtmeters > -</ zichtmeters >< windstotenMS > 6.4 </ windstotenMS >< regenMMPU > -</ regenMMPU >< zonintensiteitWM2 > -</ zonintensiteitWM2 >< icoonactueel ID = \"cc\" zin = \"Zwaar bewolkt\" >https://www.buienradar.nl/resources/images/icons/weather/30x30/cc.png</ icoonactueel >< temperatuur10cm > 18.2 </ temperatuur10cm >< url >http://www.buienradar.nl/nederland/weerbericht/weergrafieken/6391</ url >< latGraden > 51.83 </ latGraden >< lonGraden > 6.33 </ lonGraden ></ weerstation > ");
  • Not sure but I think [this](https://stackoverflow.com/questions/291387/walking-an-xml-tree-in-c-sharp) will help you to build a tree from a XML string. – dcg Oct 02 '17 at 18:54
  • Provide a simplified, but full, example that reproduces your problem, so we can reproduce it by ourselves. Exclude all unnesessary details. – andrew Oct 02 '17 at 19:10
  • 1
    Have you tried stepping through the code to find out what is going wrong? You can use the immediate window to execute statements to find out where the offending one is. – NightOwl888 Oct 02 '17 at 19:18
  • if details.count equals zero, then there will be no detail to foreach on. Perhaps these should occur before the foreach? – Greg Oct 02 '17 at 20:53
  • @dcg that one knows what XML file it is going to receive, that is not my purpose i want to be able to convert **any** XML file – Gijs van der Meijde Oct 03 '17 at 07:47
  • @andrew i added to examples, they return an empty node. – Gijs van der Meijde Oct 03 '17 at 07:47
  • @NightOwl888 i have, detail.Value.Trim() doesnt seem to work as i expect. – Gijs van der Meijde Oct 03 '17 at 07:47
  • @Greg it does not, when i add nodes containing a default string multiple nodes are added. – Gijs van der Meijde Oct 03 '17 at 07:47
  • Not sure what you're trying to accomplish with `details.Count() == 0 && int.TryParse(...)` - if there are no items in details, your code never enters the foreach loop. – Tieson T. Oct 03 '17 at 07:53
  • @TiesonT. you are right, that was a poor voodoo debug attempt. I dragged moved that piece of code from outside the forloop inside the forloop but forgot to remove the details.count(). – Gijs van der Meijde Oct 03 '17 at 12:43

1 Answers1

0

Based on what it seems like you're trying to do, I think this is what you're after:

public static InformationNode fromXML(String xml)
{
    xml = xml.Replace("< ", "<").Replace("</ ", "</"); //Bugfix for some API's.
    var xdoc = XDocument.Parse(xml);
    var details = xdoc.Root.Elements();
    var key = "->";

    var node = new InformationNode(key, "", InformationType.Object);

    // Do we have any child nodes?
    if(details != null && details.Any())
    {
        foreach (var detail in details)
        {
            //If XML is object, recurse:
            node.addChild(fromXML(detail.ToString()));                
        }
    }
    else
    {
        // No child nodes - try to read the current element's value
        var rootValue = xdoc.Root.Value.Trim();

        //If XML is Leaf.
        if (int.TryParse(rootValue, out var n))
        {
            node = InformationNode(key, rootValue, InformationType.Int);
        }
        else
        {
            node = InformationNode(key, rootValue, InformationType.String);
        }
    }

    return node;
}

XDocument.Root is an XElement, so if it has no child elements, you can just read it's value. You might want to add a check for a null or empty string.

I also prefer to only have one exit point in a given method, if possible, so I updated the parsing section a bit.

This is untested, unless you plan on providing the implementatin of InformationNode, etc.

Tieson T.
  • 20,774
  • 6
  • 77
  • 92
  • Thank you, it still returns an error (XmlException: Data at the root level is invalid. Line 1, position 1.) on the first recursion but at least i have the feeling it does something now. – Gijs van der Meijde Oct 03 '17 at 12:44
  • I found the recursion problem, the "detail.Value" is stripped of all xml tags, by replacing it by "detail.ToString()" my problem is fixed. Thank you very much for your help! – Gijs van der Meijde Oct 03 '17 at 13:32