I'm trying to figure out how to do a select statement using linq to xml. I'd like to return the ServerTypes if the DeploymentType equals a specific value (Enterprise9999).
XML:
<Deployments>
<Deployment>
<DeploymentType>Enterprise9999</EnterpriseDeploymentType>
<Servers>
<DeploymentServer>
<ServerType>WindowsServer</ServerType>
</DeploymentServer>
<DeploymentServer>
<ServerType>LinuxServer</ServerType>
</DeploymentServer>
</Servers>
</Deployment>
<Deployment></Deployment>
<Deployment></Deployment>
</Deployments>
Here's what I have so far in the code. I'm sure I'm going about this the wrong way:
XDocument xmlDoc = XDocument.Load(#xmlFile);
IEnumerable<XElement> xlDeployments = from depRows in xmlDoc.Descendants("Deployments")
select depRows;
var deploy = xlDeployments.Descendants("Deployment");
foreach (var dep in deploy)
{
if (dep.Element("DeploymentType").ToString() == "Enterprise9999")
{
MessageBox.Show(dep.Elements("ServerType").ToString());
}
}
Is a namespace required for a select statement?
I've changed you're enclosing tag </EnterpriseDeploymentType> to </DeploymentType>
XDocument xmlDoc = XDocument.Load(#xmlFile);
var deployments = xmlDoc.Descendants("Deployment")
.Where(dep => dep.Element("DeploymentType") != null
&& dep.Element("DeploymentType").Value == "Enterprise9999");
var servers = deployments.Descendants("ServerType")
.Select(node => node.Value);
Console.WriteLine(string.Join(Environment.NewLine, servers));
prints:
WindowsServer
LinuxServer
Assuming you've corrected your XML as per my comment, you can use the following single query: -
var nodes = from n in xml.Descendants("DeploymentType")
.Where(x => x.Element("EnterpriseDeploymentType").Value.Equals("Enterprise9999"))
select n.Descendants("Servers").Descendants("ServerType").Select(s => s.Value);
Which will give you:
WindowsServer
LinuxServer
Related
I would like to know how to parse my xml file in c# with LinQ, I made a lot of research but there isn't my precise case..
So here is my xml code :
<WindowsMediaPlayer>
<Playlist name="playlistdefouf">
<Element>
<type>Audio</type>
<name>lol</name>
</Element>
<Element>
<type>Video</type>
<name>tamere</name>
</Element>
</Playlist>
</WindowsMediaPlayer>
I would like to make a function that verify if a song exists (With type AND name) according to the right playlist too.
For example if I got in parameters playlistname = "playlistdefouf",type = "Audio" and name = "lol" my function will return 1
I already tried to do something but I think I'm lost..
XDocument xmlFile = XDocument.Load(Helper.xmlFolder + "/playlist.xml");
IEnumerable<XElement> elem = xmlFile.Root.Descendants();
IEnumerable<XElement> requete = from d in elem
where d.Name == "Playlist"
&& d.Attribute("name").Value == "playlistdefouf"
select d;
IEnumerable<XElement> requete2 = from d in requete.Descendants()
where d.Name == "Element"
select d;
IEnumerable<XElement> requete3 = from d in requete2.Descendants()
select d;
Here is how to retrieve an IEnumerable of the Playlists that have a specific type and name:
XDocument xmlFile = XDocument.Load("playlists.xml");
var res = from playlist in xmlFile.Root.Elements("Playlist")
where
playlist.Attribute("name").Value == "playlistdefouf" &&
playlist.Element("Element").Element("type").Value == "Audio" &&
playlist.Element("Element").Element("name").Value == "lol"
select playlist;
You can get a count of the playlists by using the Count() extension method
res.Count();
Or you can use the Extension method Any() instead of Count to get a boolean that is more expressive if you want to know if a list contains any elements matching your parameters.
This yields the same result but I personally prefer it structured this way:
var xml = XDocument.Load("playlist.xml");
var result = from playlist in xml.Descendants("Playlist")
where (string)playlist.Attribute("name") == "playlistdefouf"
from song in playlist.Descendants("Element")
where (string)song.Element("type") == "Audio" && (string)song.Element("name") == "lol"
select playlist;
Then you can use the IEnumerable extensions to get the results you want:
var count = result.Count();
var isExisting = result.Any();
var playlist = result.ToList();
This is my XML content:
<ListEnginsMesures>
<EnginsESC>
<NomValide>Engin_inconnu</NomValide>
<NomEquivalents>
<NomEquivalent>Engin inconnu</NomEquivalent>
<NomEquivalent>Engininconnu</NomEquivalent>
</NomEquivalents>
</EnginsESC>
<EnginsESC>
<NomValide>DRSC_6150</NomValide>
<NomEquivalents>
<NomEquivalent>DRSC 6150</NomEquivalent>
<NomEquivalent>DRSC6150</NomEquivalent>
<NomEquivalent>DRSC6.150</NomEquivalent>
<NomEquivalent>DRSC_6.150</NomEquivalent>
</NomEquivalents>
</EnginsESC>
<ListEnginsMesures>
I want to select value of 'NomValide' when i have 'NomEquivalent'.
For example :
(select 'NomValide' where 'NomEquivalent' = "Engin inconnu") will return Engin_inconnu.
(select 'NomValide' where 'NomEquivalent' = "DRSC_6.150") will return DRSC_6150.
HOW CAN I ACHIEVE THIS ONE ?
THANKS IN ADVANCE..
If you expect only one result then the following should work:
string xml=#"<ListEnginsMesures>
<EnginsESC>
<NomValide>Engin_inconnu</NomValide>
<NomEquivalents>
<NomEquivalent>Engin inconnu</NomEquivalent>
<NomEquivalent>Engininconnu</NomEquivalent>
</NomEquivalents>
</EnginsESC>
<EnginsESC>
<NomValide>DRSC_6150</NomValide>
<NomEquivalents>
<NomEquivalent>DRSC 6150</NomEquivalent>
<NomEquivalent>DRSC6150</NomEquivalent>
<NomEquivalent>DRSC6.150</NomEquivalent>
<NomEquivalent>DRSC_6.150</NomEquivalent>
</NomEquivalents>
</EnginsESC>
</ListEnginsMesures>";
var xe = XElement.Parse(xml);
var result = xe.Elements("EnginsESC")
.Where
(
x=>
x.Element("NomEquivalents")
.Elements("NomEquivalent")
.Any(n=>(string)n=="Engin inconnu")
)
.Select(x=>(string)x.Element("NomValide"))
.FirstOrDefault();
If you expect more than one results:
var results = xe.Elements("EnginsESC")
.Where
(
x=>
x.Element("NomEquivalents")
.Elements("NomEquivalent")
.Any(n=>(string)n=="Engin inconnu")
)
.Select(x=>(string)x.Element("NomValide"));
To my great frustration, I spent half a day to build some queries for an XML document and I don't know anything more than I knew before I started. So, I'm taking the easy way out and ask again for help.
The XML code is like this:
<?xml version="1.0" ?>
<Main>
<alpha Id = "AlphaId_1">
<beta>AlphaId1_Beta</beta>
<gamma>AlphaId1_Gama</gamma>
<delta Type = "A">AlphaId1_DeltaTypeA</delta>
<delta Type = "B">AlphaId1_DeltaTypeB</delta>
<kapa Id="01">
<description>AlphaId1_KapaId1_Descr</description>
<name>AlphaId1KapaId1_Name</name>
<teta>AlphaId1KapaId1_Teta</teta>
</kapa>
<kapa Id="02">
<description>AlphaId1KapaId2_Descr</description>
<name>AlphaId1KapaId2_Name</name>
<teta>AlhaId1KapaId2_Teta</teta>
</kapa>
</alpha>
<alpha Id = "AlphaId_2">
<beta>AlphaId2_Beta</beta>
<gamma>AlphaId2_Gama</gamma>
<delta Type = "A">AlphaId2_DeltaTypeA</delta>
<delta Type = "B">AlphaId2_DeltaTypeB</delta>
<kapa Id="01">
<description>AlphaId2_KapaId1_Descr</description>
<name>AlphaId2KapaId2_Name</name>
<teta>AlphaId2KapaId2_Teta</teta>
</kapa>
<kapa Id="02">
<description>AlphaId1KapaId2_Descr</description>
<name>AlphaId2KapaId2_Name</name>
<teta>AlhaId2KapaId2_Teta</teta>
</kapa>
</alpha>
</Main>
I am looking for a query to retrieve for example the value "AlphaId2_DeltaTypeA".
The second query should retrieve all the description values from every KapaId for a selected AlphaId.
The only code I could come up with is
XDocument xdoc = XDocument.Load(#"doc.xml");
IEnumerable<XElement> list1 = xdoc.Root.Descendants("delta");
var cifmi =
from el in list1
where (string)el.Attribute("Type") == "A"
select el;
foreach (XElement el in cifmi)
{
textBox1.AppendText(el.Value + System.Environment.NewLine);
}
The code finds two values instead of one.
var xDoc = XDocument.Load("Input.txt");
var alpha = (from a in xDoc.Root.Elements("alpha")
let deltas = a.Elements("delta")
let deltaA = deltas.First(x => (string)x.Attribute("Type") == "A")
where (string)deltaA == "AlphaId2_DeltaTypeA"
select a).First();
var descriptions = alpha.Elements("kapa")
.Select(x => (string)x.Element("description")).ToList();
It will only look for <delta> which has both Type="A" and value of AlphaId2_DeltaTypeA. If you only care about value try that one:
var alpha = (from a in xDoc.Root.Elements("alpha")
let deltas = a.Elements("delta")
where deltas.Any(x => (string)x == "AlphaId2_DeltaTypeA")
select a).First();
Update
*alpha Id == "AlphaId_1" and delta Type = "A" and the answer is AlphaId1_DeltaTypeA*
var alpha = (string)xDoc.Root
.Elements("alpha")
.First(x => (string)x.Attribute("Id") == "AlphaId_1")
.Elements("delta")
.First(x => (string)x.Attribute("Type") == "A");
xDoc variable loads the XML content but I am not able to retrieve any information. It comes back NULL:
var xDoc = XDocument.Load(Config.CredentialFileName);
//method 1
IEnumerable<XElement> rows = from row in xDoc.Descendants("domain")
where (string)row.Attribute("name") == "TEST"
select row;
//method 2
var list = xDoc.Descendants("domain")
.Select(d => new
{
name = d.Attribute("name").Value,
username = d.Attribute("username").Value,
password = d.Attribute("password").Value //,
})
.Where(a => a.name == "TEST")
.ToList();
XML file:
<domains>
<domain name="TEST" userName="test" password="tSEvmlsmwEkjSxUwrCVf3G6"/>
</domains>
Thank you
Your first method works just fine with xml you provided. Make sure you are parsing xml with exactly same structure. Also check that you have at least one domain element with name equal to TEST. And make sure you don't have namespaces defined in your xml.
Second method has typo in userName attribute name (you have lower case username):
var list = xDoc.Descendants("domain")
.Select(d => new {
name = d.Attribute("name").Value,
username = d.Attribute("userName").Value, // <-- typo here
password = d.Attribute("password").Value
})
.Where(a => a.name == "TEST")
.ToList();
Also, I'd recommend to use casting instead of reading node Value property, because getting this property will throw an exception if node not exist.
var domains = from d in xDoc.Descendants("domain")
let name = (string)d.Attribute("name")
where name == "TEST"
select new {
Name = name,
Username = (string)d.Attribute("userName"),
Password = (string)d.Attribute("password")
};
See below.
var xDoc= XElement.Load(Config.CredentialFileName);
var result = xDoc.Elements("domain").Where(x => x.Attribute("name").Value.Equals("TEST")).ToList();
I want my XElements in document order.
Can I reorder my xpathGroups using Join like in this example?
XDocument message_doc = XDocument.Load(message);
var xpathGroups =
from e in contextErrors
group e by SelectElement(message_doc, e.XPath) into g
select new
{
Element = g.Key,
ErrorItems = g,
};
var documentOrderedGroups =
from elem in message_doc.Root.DescendantsAndSelf()
join e in xpathGroups on elem equals e.Element
select e;
Message:
<root>
<a>
<aa>
<aaa>9999</aaa>
</aa>
<aa>
<aaa>8888</aaa>
</aa>
</a>
<b>
<bb>
<bbb>7777</bbb>
</bb>
</b>
<c>
<cc>
<ccc>6666</ccc>
</cc>
</c>
</root>
Input data:
/root/c[1]/cc[1]/ccc[1]
/root/a[1]/aa[2]/aaa[1]
/root/b[1]/bb[1]/bbb[1]
/root/a[1]/aa[1]/aaa[1]
Expected result:
/root/a[1]/aa[1]/aaa[1]
/root/a[1]/aa[2]/aaa[1]
/root/b[1]/bb[1]/bbb[1]
/root/c[1]/cc[1]/ccc[1]
Your original queries work, and the result is an object with the element and its relevant XPath query in document order. However, the result conflicts with the comment you made that you only want the elements in document order.
Elements and XPath: if you want both the element and its XPath then the join will remain as part of the query but I would replace the grouping with a projection into an anonymous type.
var xpathElements = contextErrors.Select(e => new
{
Element = message_doc.XPathSelectElement(e.XPath),
XPath = e.XPath
});
var ordered = from e in message_doc.Descendants()
join o in xpathElements on e equals o.Element
select o;
Elements only: if you only want the elements to be in document order, the following approach would work as well.
var xpathElements = contextErrors.Select(e => message_doc.XPathSelectElement(e.XPath));
var ordered = message_doc.Descendants()
.Where(e => xpathElements.Any(o => e == o));
In both examples I've used the XPathSelectElement method to take the place of your
SelectElement method, which I gather has the same purpose.