0

I have to read the value from XML in C# based on some conditions. Below is my sample xml

<Properties>

    <prop1 Name = " Apple" Defaultvalue="red">
         <childprop Name = "special" Value="pink" >
         </childprop>
    </prop1>
    <prop1 Name = " Orange"  Defaultvalue="orange">     
    </prop1>
    <prop1 Name = "Banana" Defaultvalue="yellow">
        <childprop Name = "raw" Value="green" >
        </childprop>
        <childprop Name = "special" Value="red" >
        </childprop>
    </prop1>  
</Properties>

For eg, if input is Orange, return value is defaultvalue = "Orange"

If the input is Banana, then return will be based on 2nd input. If it is Banana, raw, - return green if it is Banana, blank - return yellow if it is Banana, long - return yellow (No match for "long" so return default value at parent level).

What is the best way to achieve this.

2
  • There might be a way to search this through XPath, but I'm not sure what the syntax would be for the query. Commented Jul 2, 2019 at 17:55
  • Yes, I am not getting that either Commented Jul 2, 2019 at 17:57

4 Answers 4

1

Using Linq2xml help you:

var workflowXml = @"
    <Properties>
        <prop1 Name = ""Apple"" Defaultvalue=""red"">
            <childprop Name = ""special"" Value=""pink"" >
            </childprop>
        </prop1>
        <prop1 Name = ""Orange""  Defaultvalue=""orange"">     
        </prop1>
        <prop1 Name = ""Banana"" Defaultvalue=""yellow"">
            <childprop Name = ""raw"" Value=""green"" >
            </childprop>
            <childprop Name = ""special"" Value=""red"" >
            </childprop>
        </prop1>  
    </Properties>";

var xmlDoc = XDocument.Parse(workflowXml);
var xmlCurrentLevelElement = xmlDoc.Element("Properties");
var stepNumber = 1;

while (true)
{
    var options = xmlCurrentLevelElement
        .Elements()
        .Select(e => e.Attributes().FirstOrDefault(a => a.Name == "Name"))
        .Where(a => a != null)                    
        .ToArray();

    if (!options.Any())
    {
        var currentValue = xmlCurrentLevelElement
            .Attributes()
            .FirstOrDefault(a => a.Name == "Value" || a.Name == "Defaultvalue")
            ?.Value ?? "value not defined";

        Console.WriteLine($"no more options: {currentValue}");
        break;
    }

    var hints = string.Join(" or ", options.Select(a => a.Value));

    Console.WriteLine($"step {stepNumber}: input any value from '{hints}' - ");
    var value = Console.ReadLine();

    var xmlNextLevelElement = options
        .FirstOrDefault(a => a.Value == value)
        ?.Parent ?? null;

    if (xmlNextLevelElement == null)
    {
        var defaultValue = xmlCurrentLevelElement
            .AncestorsAndSelf()
            .Select(e => e.Attributes().FirstOrDefault(a => a.Name == "Defaultvalue"))
            .Where(a => a != null)
            .FirstOrDefault()
            ?.Value ?? "default value not defined";

        Console.WriteLine($"no match: {defaultValue}");
        break;
    }

    xmlCurrentLevelElement = xmlNextLevelElement;
    stepNumber++;
}
Sign up to request clarification or add additional context in comments.

Comments

1

Another LINQ to XML sample. And a reference to the Microsoft Docs.

using System;
using System.Linq;
using System.Xml.Linq;

public class Program
{
    public static void Main()
    {

        Find("Apple");
        Find("Banana,raw");  
        Find("Banana, ");
    }

    public static void Find(string input)
    {
        var xml = @"<Properties>
            <prop1 Name = ""Apple"" Defaultvalue=""red"">
                 <childprop Name = ""special"" Value=""pink"" >
                 </childprop>
            </prop1>
            <prop1 Name = ""Orange""  Defaultvalue=""orange"">     
            </prop1>
            <prop1 Name = ""Banana"" Defaultvalue=""yellow"">
                <childprop Name = ""raw"" Value=""green"" >
                </childprop>
                <childprop Name = ""special"" Value=""red"" >
                </childprop>
            </prop1>  
        </Properties>";

        var doc = XElement.Parse(xml);

        var keywords = input.Split(',');

        XElement match = null;
        foreach (var key in keywords){
            var node = (from n in (match??doc).Descendants()
                where (string)n.Attribute("Name") == key
                select n).FirstOrDefault();
            match = node??match;
        }
        if (match != null)
            Console.WriteLine(((string) match.Attribute("Defaultvalue"))??((string)match.Attribute("Value")));
        else
            Console.WriteLine("Nothing Found.");
    }
}

Running in .Net Fiddle

Comments

1

Here's a single query version:

var document = XDocument.Parse(xml);

var dictionaries =
    document
        .Root
            .Elements("prop1")
            .Select(prop1 => new
            {
                name = prop1.Attribute("Name").Value,
                children =
                    prop1
                        .Elements("childprop")
                        .Select(childprop => new
                        {
                            name = childprop.Attribute("Name").Value,
                            value = childprop.Attribute("Value").Value
                        })
                        .StartWith(new
                        {
                            name = "",
                            value = prop1.Attribute("Defaultvalue").Value
                        })
            })
            .ToDictionary(
                x => x.name,
                x => x.children.ToDictionary(y => y.name, y => y.value));

When I write this:

Console.WriteLine(dictionaries["Apple"][""]);
Console.WriteLine(dictionaries["Apple"]["special"]);
Console.WriteLine(dictionaries["Banana"][""]);
Console.WriteLine(dictionaries["Banana"]["raw"]);
Console.WriteLine(dictionaries["Banana"]["special"]);   

I get this:

red
pink
yellow
green
red

Comments

0

Using Linq

 String result = string.Empty;

var exist = xdoc.Descendants("Properties").Descendants("prop1").Attributes("Name").Where(x => x.Value.Equals(value)).FirstOrDefault();

  if (exist != null) 
  {
   XElement xElement = xdoc.Descendants("prop1").Where(x => x.Attribute("Name").Value.Equals(value).Select(x => x).FirstOrDefault();

   var childPropsExist = xElement.Elements("childprop").Any();

   if (childPropsExist) //we will be needing second input
   {

    result = xElement.Elements("childprop").Attributes("Name").Where(x => x.Value.Equals(secondInput)).FirstOrDefault().NextAttribute.Value;

   } else {
    result = exist.NextAttribute.Value; //Default value;
   }
  }

return result;

2 Comments

Thanks for the LINQ method. I just figured out with an elaborate for loop.I will try this LINQ now.
other answers are great as well.

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.