How can I get the value of a Node in a XDocument when don't has more childs ?
<Contacts>
<Company>
<Name>Testing</Name>
<ID>123</ID>
</Company>
</Contacts>
In this case, I wanna get the value of the <Name> and <ID> element, because don't has child elements in them.
I'm trying the follow
protected void LeXMLNode(HttpPostedFile file)
{
XmlReader rdr = XmlReader.Create(file.FileName);
XDocument doc2 = XDocument.Load(rdr);
foreach (var name in doc2.Root.DescendantNodes().OfType<XElement>().Select(x => x.Name).Distinct())
{
XElement Contact = (from xml2 in doc2.Descendants(name.ToString())
where xml2.Descendants(name.ToString()).Count() == 0
select xml2).FirstOrDefault();
string nome = name.ToString();
}
}
but without success, because my foreach pass in all Elements and I wanna get just the value of Elements that don't has childs.
document.Root.Elements("Company").Elements()
.Where(item => !item.HasElements).ToList();
See XElement.HasElements: http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.haselements.aspx
Related
Below is my XML file
<MultiCentreDeals>
<DealItem>
<ID>24</ID>
<Days>
<Day>
<DayID>24-1</DayID>
<DayTitle>Day 13</DayTitle>
<Title>Meeting Point</Title>
<HotelName>15</HotelName>
</Day>
<Day>
<DayID>24-2</DayID>
<DayTitle>Day 2</DayTitle>
<Title>Departure to Test</Title>
<HotelName>54</HotelName>
</Day>
</Days>
</DealItem>
</MultiCentreDeals>
I want to delete the XML node set belong to ID 24 and DayID 24-2. Can anyone explain how to do this.
XDocument is your friend.
// Parse your XML string
var doc = XDocument.Parse(xml);
// Find the first child of type "Day", whose child of type "DayID" has the value "24-2"
var toRemove = doc.Root
.Descendants("Day")
.FirstOrDefault(x => x.Element("DayID").Value == "24-2");
// Remove it
toRemove?.Remove();
string result = doc.ToString();
Here is my xml file
<?xml version="1.0" encoding="ASCII"?>
<Vitals>
<Vendor>General Electric Healthcare</Vendor>
<Model>Pro/Procare</Model>
<Result name="Mean_arterial_pressure">
<Value>86</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Systolic_blood_pressure">
<Value>130</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Diastolic_blood_pressure">
<Value>67</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Pulse">
<Value>73</Value>
<Units name="BPM"></Units>
<Method>blood_pressure</Method>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
</Vitals>
and Here is my sourcecode, I having the issue how to get the result name and the value?
private void btnReadXml_Click(object sender, EventArgs e)
{
Hashtable h = new Hashtable();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("C:\\dinamap.xml");
XmlNodeList doc_results = xmlDoc.GetElementsByTagName("Vitals/Vendor/Model/Result[#name='Systolic_blood_pressure']");
foreach (XmlNode pnode in doc_results)
{
foreach (XmlNode cnode in pnode.ChildNodes)
{
if (cnode.Name == "Value")
{
h.Add(pnode.Attributes["name"].InnerText + cnode.Name, cnode.Attributes["name"].InnerText);
}
else
{
h.Add(pnode.Attributes["name"].InnerText + "_" + cnode.Name, cnode.InnerText);
}
}
}
}
May I know what wrong of my code? always can't get the value.
I need to get the value from xml file.
On line 5, your xPath specify Model is a child of Vendor while Vendor contains only a string (<Vendor>General Electric Healthcare</Vendor>).
Moreover, to navigate with xPath i advice you to use SelectNodes function.
Try this instead :
XmlNodeList doc_results = xmlDoc.SelectNodes("/Vitals/Model/Result[#name='Systolic_blood_pressure']");
It'd be easier if you used LINQ to XML for this.
var doc = XDocument.Load("path/to/xml");
var results =
from result in doc.Descendants("Result")
select new
{
Name = (string) result.Attribute("name"),
Value = (string) result.Element("Value"),
Units = (string) result.Element("Units").Attribute("name")
};
You could then filter by Name if you needed:
var sysBp = results.Single(x => x.Name == "Systolic_blood_pressure");
See this fiddle for a working demo.
You're currently trying to retrieve the "name" attribute of the child node, which it does not actually have in the case of your value node. If you use cnode.Value you can get the contents of a text note.
Also, Result is not a child of Model, which is not a child of Vendor. You'll either want to properly make them children or change the path you're setting for doc_results
private void btnReadXml_Click(object sender, EventArgs e)
{
var doc = XDocument.Load("C:\\dinamap.xml");
var results = from result in doc.Descendants("Result")
select new
{
Name = (string)result.Attribute("name"),
Value = (string)result.Element("Value"),
Units = (string)result.Element("Units").Attribute("name")
};
foreach (var result in results)
{
MessageBox.Show("{result.Name}: {result.Value} {result.Units}");
}
}
<test>
<acc id="1"> acc1 </acc>
<acc id="2"> acc2 </acc>
<acc id="3"> acc3 </acc>
<acc id="4"> acc4 </acc>
</test>
For example, if I want to take the value of each <acc> element:
var iAccs = xdoc.Descendants("test").Elements("acc").Select(p => p.Value);
List<string> myList = new List<string>();
foreach(string p in iAccs)
{
myList.Add(p);
}
But how to substract all the attribute "id" values of each <acc> elements?
You can easily get this using LINQ-to-XML:-
XDocument xdoc = XDocument.Load(#"You XML file path");
List<string> result = xdoc.Descendants("acc")
.Select(x => (string)x.Attribute("id")).ToList();
Or if you prefer query syntax then:-
List<int> result2 = (from x in xdoc.Descendants("acc")
select (int)x.Attribute("id")).ToList();
I want to remove parent elements from an XML structure if child is empty.
My XML:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
<Status>single</Status>
</Customer>
<customer>
<Name>Jack</Name>
<Age></Age>
<Status></Status>
</Customer>
</Customers>
Should become:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
<Status>single</Status>
</Customer>
</Customers>
my code :
XmlElement element3 = xmlDocument.CreateElement("Age");
element3.InnerText = str3;
element1.AppendChild((XmlNode)element3);
XmlElement element4 = xmlDocument.CreateElement("Status");
element4.InnerText = str4;
element1.AppendChild((XmlNode)element4);
How can I remove the parent "customer", if age and status child are empty?
You can use XPath syntax along with SelectNodes() method to get specific nodes from XmlDocument easily.
Example to select <Customer> elements having child node <Age> and <Status> empty, then remove those selected elements :
var nodes = xmlDocument.DocumentElement.SelectNodes("//Customer[Age = '' and Status = '']");
foreach (XmlElement node in nodes)
{
node.ParentNode.RemoveChild(node);
}
UPDATE :
It seems that you're the one that construct the XML. So i'd suggest to check if str3 and str4 are empty, and if they are remove corresponding <Customer> element :
if(string.IsNullOrEmpty(str3) && string.IsNullOrEmpty(str4))
{
element1.ParentNode.RemoveChild(element1);
}
I understand that you're creating a new file and adding each element after the validation. I think this should work for you:
XDocument input = XDocument.Load("customers.xml");
XDocument output = new XDocument();
output.Add(new XElement("Customers"));
IEnumerable<XElement> elements = input.Element("Customers").Elements("customer");
foreach (XElement el in elements)
{
string age = el.Element("Age").Value;
string status = el.Element("Status").Value;
if (age != "" || status != "")
{
output.Element("Customers").Add(el);
}
}
output.Save("customers.xml");
I would like to filter with high performance XML elements from an XML document.
Take for instance this XML file with contacts:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="asistentes.xslt"?>
<contactlist evento="Cena Navidad 2010" empresa="company">
<contact type="1" id="1">
<name>Name1</name>
<email>xxxx#zzzz.es</email>
<confirmado>SI</confirmado>
</contact>
<contact type="1" id="2">
<name>Name2</name>
<email>xxxxxxxxx#zzzze.es</email>
<confirmado>Sin confirmar</confirmado>
</contact>
</contaclist>
My current code to filter from this XML document:
using System;
using System.Xml.Linq;
class Test
{
static void Main()
{
string xml = #" the xml above";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("contact")) {
Console.WriteLine(element);
var id = element.Attribute("id").Value;
var valor = element.Descendants("confirmado").ToList()[0].Value;
var email = element.Descendants("email").ToList()[0].Value;
var name = element.Descendants("name").ToList()[0].Value;
if (valor.ToString() == "SI") { }
}
}
}
What would be the best way to optimize this code to filter on <confirmado> element content?
var doc = XDocument.Parse(xml);
var query = from contact in doc.Root.Elements("contact")
let confirmado = (string)contact.Element("confirmado")
where confirmado == "SI"
select new
{
Id = (int)contact.Attribute("id"),
Name = (string)contact.Element("name"),
Email = (string)contact.Element("email"),
Valor = confirmado
};
foreach (var contact in query)
{
...
}
Points of interest:
doc.Root.Elements("contact") selects only the <contact> elements in the document root, instead of searching the whole document for <contact> elements.
The XElement.Element method returns the first child element with the given name. No need to convert the child elements to a list and take the first element.
The XElement and XAttribute classes provide a wide selection of convenient conversion operators.
You could use LINQ:
foreach (XElement element in doc.Descendants("contact").Where(c => c.Element("confirmado").Value == "SI"))