I have an XML file with subelements of elements:
<Root>
<Location>
<DepartureBoundary>
<DepartureBoundaryRadius>600</DepartureBoundaryRadius>
</DepartureBoundary>
</Location>
<Location>
<DepartureBoundary>
<DepartureBoundaryRadius>600</DepartureBoundaryRadius>
</DepartureBoundary>
</Location>
</Root>
Currently, I am doing the following to access the value for DepartureBoundaryRadius:
XDocument locationsDoc = XDocument.Load("file.xml");
DepartureLocationBoundaryRadius = null;
List<DepartureBoundaryRadius> radiusList = new List<DepartureBoundaryRadius>();
foreach (XElement locationElement in locationsDoc.Descendants("Root"))
{
foreach (XElement locationSubElement in locationsDoc.Descendants("Location"))
{
foreach (XElement departureElement in locationsDoc.Descendants("DepartureBoundary"))
{
DepartureLocationBoundaryRadius = departureElement.Element("DepartureRadius").Value));
radiusList.Add(DepartureLocationBoundaryRadius);
}
}
}
Is there an easier way to do this? I would rather assign the value of DepartureLocationBoundaryRadius in one line or one statement -- especially since each Location has only one DepartureBoundaryRadius value. Any thoughts? Thanks!
I think you mean Elements in your question . Descendants already gives what you want
var values = locationsDoc.Descendants("DepartureBoundaryRadius")
.Select(x => x.Value)
.ToList();
var list = xdoc.Document.Descendants("DepartureBoundaryRadius").Select(x=>x.Value);
Related
I have XML Code Block as below (it is part of similar lines of hundreds..):
<specs>
<spec name='fald' value = '100'>
<name></name>
<value></value>
</spec>
</specs>
I need to convert code as seen below:
<specs>
<spec name ='fald' value = '100'/>
</specs>
Using following code I am able to delete child nodes:
foreach (XElement child in doc.Descendants().Reverse())
{
if (child.HasAttributes)
{
foreach (var attribute in child.Attributes())
{
if (string.IsNullOrEmpty(attribute.Value) && string.IsNullOrEmpty(child.Value))
child.Remove();
}
}
}
But this process also deletes parent node ('spec') which is expected to take place there. Any help is appreciated, thanks...
It's a little unclear what the criteria for deleting an element is, but to get you started, perhaps this is somewhere along the lines of what you are looking for?
var xml =
#"<specs>
<spec name='fald' value='100'>
<name></name>
<value></value>
</spec>
</specs>";
var doc = XElement.Parse(xml);
var childrenToDelete = doc.XPathSelectElements("//spec/*")
.Where(elem => string.IsNullOrEmpty(elem.Value)
&& (!elem.HasAttributes
|| elem.Attributes().All(attr => string.IsNullOrEmpty(attr.Value))))
.ToList();
foreach (var child in childrenToDelete)
{
child.Remove();
}
// Produces:
// <specs>
// <spec name="fald" value="100" />
// </specs>
Check this fiddle for a test run.
Having an issue grabbing values in an XML file
The structure is as followed
<configuration>
<settings>
<add key="folder" value = "c:\...." />
</settings>
</configuration>
i want to be able to read the value from folder.
string val = string.Empty;
foreach (XElement element in XElement.Load(file).Elements("configuration"))
{
foreach (XElement element2 in element.Elements("settings"))
{
if (element2.Name.Equals("folder"))
{
val = element2.Attribute(key).Value;
break;
}
}
}
return val;
The name of the element isn't folder... that's the value of the key attribute. Also note that as you've used XElement.Load, the element is the configuration element - asking for Elements("configuration") will give you an empty collection. You could either load an XDocument instead, or just assume you're on a configuration element and look beneath it for settings.
I think you want:
return XElement.Load(file)
.Elements("settings")
.Elements("add")
.Where(x => (string) x.Attribute("key") == "folder")
.Select(x => (string) x.Attribute("value"))
.FirstOrDefault();
You can use XPath:
var folder = XElement.Load(file)
.XPathSelectElements("/settings/add[#key='folder']")
.Select(a => (string)a.Attribute("value"))
.FirstOrDefault();
I know this is probably a lot easier than I'm making it. I'm able to pull all the machines out of the XElement but I'm trying to figure out how to pull out the machines with a specific sequence number. In the below XML snippet, I'd like to use the machines where sequence = 1.
XML:
<Location>
<Sequence>1</Sequence>
<Machines>
<Machine></Machine>
<Machine></Machine>
</Machines>
</Location>
<Location>
<Sequence>2</Sequence>
<Machines>
<Machine></Machine>
<Machine></Machine>
</Machines>
</Location>
Code:
IEnumerable<XElement> locSeqMachines =
from seq in LocationRows.Descendants("Location")
select seq;
var eMachines = locSeqMachines.Descendants("Machine");
foreach (var machine in eMachines)
{
}
Something like this should do the job:
int soughtId = 1; // Assuming this is coming from somewhere
string soughtIdStr = soughtId.ToString();
var machines = LocationRows.Descendants("Location")
.Where(l => (string)l.Element("Sequence") ==
soughtIdStr)
.Descendants("Machine");
You can use XPath to select the nodes by a specific sequence:
XmlNodeList nodeList = root.SelectNodes("descendant::Location[Sequence='1']");
This code will group all the Machine data out of a Location tag filtered on the Location's Sequence value:
var locSeqMachines = from seq in LocationRows.Descendants("Location")
where seq.Element("Sequence").Value == "1"
select new {
Sequence = seq.Element("Sequence").Value,
Machines = from m in seq.Descendants("Machines").Elements()
select m.Value
};
Here's some code demonstrating how you can access the data (and test the snippet):
foreach (var location in locSeqMachines) {
Console.WriteLine("sequence: {0}", location.Sequence);
foreach (var machine in location.Machines) {
Console.WriteLine(" machine: {0}", machine);
}
}
In parsing the given xml, you can use this method to arrive with the answer without raising an error of multiple root elements.
var xmlText = #"<root>
<Location>
<Sequence>1</Sequence>
<Machines>
<Machine></Machine>
<Machine></Machine>
</Machines>
</Location>
<Location>
<Sequence>2</Sequence>
<Machines>
<Machine></Machine>
<Machine></Machine>
</Machines>
</Location>
</root>";
var elements = XElement.Parse(xmlText);
var machineWith1 = from subElem in elements.Elements("Location")
where subElem.Element("Sequence").Value == "1"
select subElem.Element("Machines").Elements("Machine");
then you can check the value of machineWith1 for this,
I have this XML file:
<MyXml>
<MandatoryElement1>value</MandatoryElement1>
<MandatoryElement2>value</MandatoryElement2>
<MandatoryElement3>value</MandatoryElement3>
<CustomElement1>value</CustomElement1>
<CustomElement2>value</CustomElement2>
<MyXml>
All 3 elements that are called 'MandatoryElementX' will always appear in the file. The elements called 'CustomElementX' are unknown. These can be added or removed freely by a user and have any name.
What I need is to fetch all the elements that are not MandatoryElements. So for the file above I would want this result:
<CustomElement1>value</CustomElement1>
<CustomElement2>value</CustomElement2>
I don't know what the names of the custom elements may be, only the names of the 3 MandatoryElements, so the query needs to somehow exclude these 3.
Edit:
Even though this was answered, I want to clarify the question. Here is an actual file:
<Partner>
<!--Mandatory elements-->
<Name>ALU FAT</Name>
<InterfaceName>Account Lookup</InterfaceName>
<RequestFolder>C:\Documents and Settings\user1\Desktop\Requests\ALURequests</RequestFolder>
<ResponseFolder>C:\Documents and Settings\user1\Desktop\Responses</ResponseFolder>
<ArchiveMessages>Yes</ArchiveMessages>
<ArchiveFolder>C:\Documents and Settings\user1\Desktop\Archive</ArchiveFolder>
<Priority>1</Priority>
<!--Custom elements - these can be anything-->
<Currency>EUR</Currency>
<AccountingSystem>HHGKOL</AccountingSystem>
</Partner>
The result here would be:
<Currency>EUR</Currency>
<AccountingSystem>HHGKOL</AccountingSystem>
You can define a list of mandatory names and use LINQ to XML to filter:
var mandatoryElements = new List<string>() {
"MandatoryElement1",
"MandatoryElement2",
"MandatoryElement3"
};
var result = xDoc.Root.Descendants()
.Where(x => !mandatoryElements.Contains(x.Name.LocalName));
Do you have created this xml or do you get it by another person/application?
If it's yours I would advise you not to number it. You can do something like
<MyXml>
<MandatoryElement id="1">value<\MandatoryElement>
<MandatoryElement id="2">value<\MandatoryElement>
<MandatoryElement id="3">value<\MandatoryElement>
<CustomElement id="1">value<\CustomElement>
<CustomElement id="2">value<\CustomElement>
<MyXml>
In the LINQ-Statement you don't need the List then.
Your question shows improperly formatted XML but I am assuming that is a typo and the real Xml can be loaded into the XDocument class.
Try this...
string xml = #"<MyXml>
<MandatoryElement1>value</MandatoryElement1>
<MandatoryElement2>value</MandatoryElement2>
<MandatoryElement3>value</MandatoryElement3>
<CustomElement1>value</CustomElement1>
<CustomElement2>value</CustomElement2>
</MyXml> ";
System.Xml.Linq.XDocument xDoc = XDocument.Parse(xml);
var result = xDoc.Root.Descendants()
.Where(x => !x.Name.LocalName.StartsWith("MandatoryElement"));
lets say TestXMLFile.xml will contain your xml,
XElement doc2 = XElement.Load(Server.MapPath("TestXMLFile.xml"));
List<XElement> _list = doc2.Elements().ToList();
List<XElement> _list2 = new List<XElement>();
foreach (XElement x in _list)
{
if (!x.Name.LocalName.StartsWith("Mandatory"))
{
_list2.Add(x);
}
}
foreach (XElement y in _list2)
{
_list.Remove(y);
}
I'm trying to traverse an XML document and select certain node attributes. The XML is dynamically generated.
<?xml version="1.0" encoding="ISO-8859-1"?>
<streams>
<stream>
<title>+23 (Panama)</title>
<info resolution="768x420" bitrate="1000kbps"/> ----- Need These
<swfUrl>http://www.freeetv.com/script/mediaplayer/player.swf</swfUrl>
<link>rtmp://200.75.216.156/live/</link>
<pageUrl>http://www.freeetv.com/</pageUrl>
<playpath>livestream</playpath>
<language>Music</language>
<advanced></advanced>
</stream>
</streams>
The code that I'm trying to use with zero luck and Visual Studio saying "No you're wrong. Try 600 more times" is
xDoc.Load("http://127.0.0.1/www/xml.php");
XmlNodeList nodes = xDoc.SelectNodes("/streams/stream");
foreach (XmlNode xn in nodes)
{
ListViewItem lvi = listView1.Items.Add(xn["title"].InnerText);
lvi.SubItems.Add(xn["swfUrl"].InnerText);
lvi.SubItems.Add(xn["link"].InnerText);
lvi.SubItems.Add(xn["pageUrl"].InnerText);
lvi.SubItems.Add(xn["playpath"].InnerText);
lvi.SubItems.Add(xn["language"].InnerText);
lvi.SubItems.Add(xn["advanced"].InnerText);
lvi.SubItems.Add(xn["//info/#resolution"].Value);
}
Please tell me oh wise ones what am I doing wrong?
If you want to select node's attribute using XPath you should use SelectSingleNode method, e.g.:
xn.SelectSingleNode("info/#resolution").Value
To select resolution attribute of your last node you need to use:
xn["info"].Attributes["resolution"].Value
Alternatively, you can try LINQ to XML for the same results (I find its API easier to use):
var doc = XDocument.Parse("http://127.0.0.1/www/xml.php");
foreach (var d in doc.Descendants("stream"))
{
ListViewItem lvi = listView1.Items.Add(d.Element("title").Value);
lvi.SubItems.Add(d.Element("swfUrl").Value);
// ...
vi.SubItems.Add(d.Element("info").Attribute("resolution").Value);
}
Here is an example of LINQ to XML to extract attributes from the entire document of a particular attribute name OR list of attribute names.
var xml = XElement.Parse("http://127.0.0.1/www/xml.php");
// find all attributes of a given name
var attributes = xml
.Descendants()
.Attributes("AttributeName")
// find all attributes of multiple names
var attributes = xml
.Descendants()
.Attributes()
.Where(a => ListOfAttribNames.Contains(a.Name.LocalName))
Replace:
lvi.SubItems.Add(xn["//info/#resolution"].Value);
with:
lvi.SubItems.Add(xn.SelectSingleNode("info/#resolution").Value);