Rico Strydom
Rico Strydom

Reputation: 571

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();

Upvotes: 2

Views: 64

Answers (2)

Yitzhak Khabinsky
Yitzhak Khabinsky

Reputation: 22293

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

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1503040

I wouldn't use XPath for this, to be honest. I'd do it in two steps for simplicity, one to get the environment, the other the application within it:

// Cast if you need to...
string environmentName = Environment1ComboBox.SelectedItem;
string applicationName = Application1ComboBox.SelectedItem;

// First get the matching environment.
var document = XDocument.Load("Environments.xml");
var environment = document.Root?
    .Elements("Environment")
    .FirstOrDefault(env => (string) env.Element("Name") == environmentName);
if (environment is null)
{
    // Report that the environment isn't found, and exit this code
}

// Now get the matching application within the environment.
var application = environment
    .Element("Applications")
    .Elements("Application")
    .FirstOrDefault(app => (string) app.Element("Name") == applicatoinName);
if (application is null)
{
    // Report that the application isn't found, and exit this code
}

// Now we can get the connection string.
string connectionString = (string) app.Element("ConnectionString");

Upvotes: 2

Related Questions