Search code examples
c#xmllambdalinq-to-xml

Linq to XML : How to get element based on other elements in file


Consider the following xml file. I would like to get the ConnectionString Element if I already have the Environment/Name value and Application/Name selected from different ComboBoxes.

<?xml version="1.0" encoding="utf-8" ?>
<Environments>
    <Environment>
        <Name>DEV</Name>
        <Applications>
            <Application>
                <Name>App1</Name>
                <DBType>Oracle</DBType>
                <ConnectionString>CS1</ConnectionString>
                <Username>user_1</Username>
                <Password>pw_1</Password>               
            </Application>
            <Application>
                <Name>App2</Name>
                <DBType>Oracle</DBType>                     
                <ConnectionString>CS2</ConnectionString>
                <Username>user_2</Username>
                <Password>pw_2</Password>
            </Application>          
        </Applications>
    </Environment>
    <Environment>
        <Name>TEST 1</Name>
        <Applications>
            <Application>
                <Name>App1</Name>
                <DBType>Oracle</DBType> 
                <ConnectionString>CS3</ConnectionString>
                <Password>pw_3</Password>               
            </Application>
            <Application>
                <Name>App2</Name>
                <DBType>Oracle</DBType>             
                <ConnectionString>CS4</ConnectionString>
                <Username>user_4</Username>
                <Password>pw_4</Password>
            </Application>  
        </Applications>
    </Environment>
</Environments>

This is what I have at the moment but it I don't get any results back.

XDocument xDocument = XDocument.Load("Environments.xml");
        IEnumerable<XElement> ConnectionString = xDocument
        .XPathSelectElements("/Environments/Environment/Applications/Application/ConnectionString")
        .Where(x => x.XPathSelectElements("/Environments/Environment/Name").All(x => x.Value.Equals(Environment1ComboBox.SelectedItem))
                && x.XPathSelectElements("/Environments/Environment/Applications/Application/Name").All(x => x.Value.Equals(Application1ComboBox.SelectedItem)))
        .ToList();

Solution

  • Here is another way via LINQ to XML by using Ancestors() method.

    It allows to go directly to the ConnectionString element in one single statement while checking its ancestors values.

    c#

    void Main()
    {
         const string FILENAME = @"e:\Temp\Environments.xml";
    
        string environmentName = "DEV"; //Environment1ComboBox.SelectedItem;
        string applicationName = "App2"; //Application1ComboBox.SelectedItem;
        
        XDocument xdoc = XDocument.Load(FILENAME);
    
        string connectionString = xdoc.Descendants("ConnectionString")?
            .Where(x => x.Ancestors("Environment").Elements("Name")
                .FirstOrDefault().Value == environmentName 
                &&
                x.Ancestors("Application").Elements("Name")
                .FirstOrDefault().Value == applicationName)
                .FirstOrDefault().Value;
        Console.WriteLine(connectionString);
    }
    

    Output

    CS2