I am looking for how to count the nodes in an XML file that contain a value of "No" as well as the total number of elements.
I have the element count working fine, but I am not sure of the logic to look inside the XML for a value to count.
To get the total count I am using:
XmlDocument readDoc = new XmlDocument();
readDoc.Load(MapPath("Results.xml"));
int count = readDoc.SelectNodes("root/User").Count;
lblResults.Text = count.ToString();
Below is my XML:
<?xml version="1.0" encoding="iso-8859-1"?>
<root>
<User>
<URL>http://www.example.com</URL>
<JSEnabled>Yes</JSEnabled>
</User>
<User>
<URL>http://www.example.com</URL>
<JSEnabled>Yes</JSEnabled>
</User>
<User>
<URL>http://www.example.com</URL>
<JSEnabled>Yes</JSEnabled>
</User>
<User>
<URL>http://www.example.com</URL>
<JSEnabled>Yes</JSEnabled>
</User>
<User>
<URL>http://www.example.com</URL>
<JSEnabled>No</JSEnabled>
</User>
XmlDocument readDoc = new XmlDocument();
readDoc.Load(MapPath("Results.xml"));
int count = readDoc.SelectNodes("root/User").Count;
lblResults.Text = count.ToString();
int NoCount = readDoc.SelectNodes("JSEnabled[. = \"No\"]").Count;
Good reference here: http://msdn.microsoft.com/en-us/library/ms256086.aspx
I am looking for how to count the
nodes in an XML file that contain a
value of "No"
In XPath:
count(/root/User[JSEnabled = 'No'])
as well as the total number of
elements.
That you already have it:
count(/root/User)
Or use the expression for selecting the nodes and any DOM method to count Node Set Result members.
Related
I am trying to modify the following XML doc (MRE) using Linq to XML:
Move the school name and address one step higher or at the level of its parent—school element.
At the same time, change its name to <School_Name> and <School_Address>.
ORIGINAL
<?xml version="1.0" encoding="utf-8"?>
<GreatGrandParent>
<GrandParent>
<Parent>
<Child>
<Name>John</Name>
<Address>California</Address>
<Sex>Male</Sex>
<Age>18</Age>
<School>
<Name>Cool School</Name>
<Address>California</Address>
</School>
</Child>
<Child>
<Name>Mary</Name>
<Address>New Orleans</Address>
<Sex>Female</Sex>
<Age>16</Age>
<School>
<Name>Pretty School</Name>
<Address>New Orleans</Address>
</School>
</Child>
<Parent>
<GrandParent>
<GreatGrandParent>
TARGET MODIFICATION
<?xml version="1.0" encoding="utf-8"?>
<GreatGrandParent>
<GrandParent>
<Parent>
<Child>
<Name>John</Name>
<Address>California</Address>
<Sex>Male/Sex>
<Age>18</Age>
<School_Name>Cool School</School_Name>
<School_Address>California</School_Address>
</Child>
<Child>
<Name>Mary</Name>
<Address>New Orleans</Address>
<Sex>Female/Sex>
<Age>16</Age>
<School_Name>Pretty School</School_Name>
<School_Address>New Orleans</School_Address>
</Child>
<Parent>
<GrandParent>
<GreatGrandParent>
HERE'S WHAT I HAVE DONE SO FAR:
XDocument doc = XDocument.Load(#"D:\Xml\Childs Profile.xml");
XElement root = doc.XPathSelectElement("//Parent");
IEnumerable<XElement> rootlists = root.Descendants("Child").ToList();
foreach (var rootlist in rootlists)
{
XElement lists = root.Element("Child");
XElement name = root.Element("Child").Element("School").Element("Name");
XElement address = root.Element("Child").Element("School").Element("Address");
list.AddFirst(name);
list.AddFirst(address);
XElement school = root.Element("Child").Element("School");
school.Remove();
}
doc.Save(#"D:\Xml\Childs Profile.xml");
ISSUES: The foreach above does not move to next child.
PENDING: Change the XName to <School_Name> and <School_Address> either before or after moving.
You can try this:
XDocument doc = XDocument.Load(#"the.xml");
var child = doc.Descendants("Child");
var school = child.Elements("School");
string name = $"{school.First().Name}_{school.Elements("Name").First().Name}";
string address = $"{school.First().Name}_{school.Elements("Address").First().Name}";
foreach (var s in school)
{
s.Parent.Add(new XElement(name, s.Element("Name").Value));
s.Parent.Add(new XElement(address, s.Element("Address").Value));
}
school.Remove();
doc.Save(#"out.xml");
I read multiple feed from many sources with C# Console, and i have this code where i load XML From sources:
XmlDocument doc = new XmlDocument();
doc.Load(sourceURLX);
XElement xdoc = XElement.Load(sourceURLX);
How to get enclosure url and show as variable?
If I understand your question correctly (I'm making a big assumption here) - you want to select an attribute from the root (or 'enclosing') tag, named 'url'?
You can make use of XPath queries here. Consider the following XML:
<?xml version="1.0" encoding="utf-8"?>
<root url='google.com'>
<inner />
</root>
You could use the following code to retrieve 'google.com':
String query = "/root[1]/#url";
XmlDocument doc = new XmlDocument();
doc.Load(sourceURLX);
String value = doc.SelectSingleNode(query).InnerText;
Further information about XPath syntax can be found here.
Edit: As you stated in your comment, you are working with the following XML:
<item>
<description>
</description>
<enclosure url="blablabla.com/img.jpg" />
</item>
Therefore, you can retrieve the url using the following XPath query:
/item[1]/enclosure[1]/#url
With xml like below
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>title</title>
<link>https://www.link.com</link>
<description>description</description>
<item>
<title>RSS</title>
<link>https://www.link.com/xml/xml_rss.asp</link>
<description>description</description>
<enclosure url="https://www.link.com/media/test.wmv"
length="10000"
type="video/wmv"/>
</item>
</channel>
</rss>
You will get url by reading attribute
var document = XDocument.Load(sourceURLX);
var url = document.Root
.Element("channel")
.Element("item")
.Element("enclosure")
.Attribute("url")
.Value;
To get multiple urls
var urls = document.Descendants("item")
.Select(item => item.Element("enclosure").Attribute("url").Value)
.ToList();
Using foreach loop
foreach (var item in document.Descendants("item"))
{
var title = item.Element("title").Value;
var link = item.Element("link").Value;
var description = item.Element("description").Value;
var url = item.Element("enclosure").Attribute("url").Value;
// save values to database
}
I am trying to delete one record from the XML based on some attribute value. My XML structure is given below:
<?xml version="1.0" encoding="utf-8"?>
<Users>
<User>
<UserId>12345</UserId>
<FirstName>abcd</FirstName>
<LastName>efgh</LastName>
<Email>Hello#hello.com</Email>
<IsAdmin>No</IsAdmin>
</User>
<User>
<UserId>67890</UserId>
<FirstName>ijklm</FirstName>
<LastName>nopqr</LastName>
<Email>world#world.com</Email>
<IsAdmin>No</IsAdmin>
</User>
<User>
<UserId>12678</UserId>
<FirstName>stuv</FirstName>
<LastName>wxyz</LastName>
<Email>foo#bar.com</Email>
<IsAdmin>Yes</IsAdmin>
</User>
</Users>
E.g if attribute value is 12345 it should delete the below record from the XML.
<User>
<UserId>12345</UserId>
<FirstName>abcd</FirstName>
<LastName>efgh</LastName>
<Email>Hello#hello.com</Email>
<IsAdmin>No</IsAdmin>
</User>
I tried below code but I am not able to delete anything from the XML.
string path = Server.MapPath("~/XML/users.xml");
XElement xEle = XElement.Load(path);
var qry = from element in xEle.Descendants()
where (string)element.Attribute("UserId").Value == "12345"
select element;
if (qry.Count() > 0)
qry.First().Remove();
xEle.Save(path);
I am unable to figure this out. Any help with be appreciated. Thank you
<UserId>12345</UserId> is a nested sub-element of <User>, not an attribute. See XML attribute vs XML element to see the difference.
Thus you need to do:
var userId = "12345";
var qry = from element in xEle.Descendants("User")
where (string)element.Element("UserId") == userId
select element;
var first = qry.FirstOrDefault();
if (first != null)
first.Remove();
Incidentally, by calling both Count() and First(), you are evaluating your query twice. FirstOrDefault() returns the first matching element, or null if the enumerable is empty, and is thus more efficient.
UserId is not attribute in the XML. Its an element
XElement xEle = XElement.Load("input.xml");
var qry = from element in xEle.Descendants()
where (string)element.Element("UserId") == "12345"
select element;
if (qry.Count() > 0)
qry.First().Remove();
xEle.Save("input.xml");
And in your snippet you are comparing 12345 int with string type
I'm navigating XML document with XPathNodeIterator, and I want to change some nodes' values.
I can't figure out how :(
Here's the code I'm using:
XPathDocument docNav = new XPathDocument(path);
XPathNavigator nav = docNav.CreateNavigator();
nav.MoveToRoot();
XPathNodeIterator itemsIterator = nav.Select("/foo/bar/item");
while (mediumsIterator.MoveNext())
{
XPathNodeIterator subitemsIterator = itemsIterator.Current.Select("SubitemsList/name");
while (subitemsIterator.MoveNext())
{
XPathNodeIterator nodesIterator = itemsIterator.Current.Select("Param");
nodesIterator.MoveNext();
String the_params = nodesIterator.Current.Value;
// check if I need to modify nodesIterator.Current.Value
// ...
// ok I do - how?
}
}
And the XML file sample:
<?xml version="1.0" encoding="utf-8"?>
<foo>
<bar>
<item>
<Param />
<SubitemsList>
<name>name one</name>
<name>name two</name>
...
</SubitemsList>
</item>
...
</bar>
</foo>
Or maybe there's a better way to do this?
I found a way:
Replace XPathDocument with XmlDocument
When I get to the needed node
...
XmlNode node = ((IHasXmlNode)nodesIterator.Current).GetNode();
node.InnerText = "new text";
I have a XML file like that:
<Users>
<User>
<Adress Name="bbbb"/>
<Adress Name="aaaa" />
</User>
</Users>
I want to sort User element's nodes in ascending order. How can I order Adress elements?
Thank you for your help.
If node is your user node:
node.Elements("Adress").OrderBy(e=>e.Attribute("Name").Value)
Are you merely wanting to work with the XML objects in memory or are you looking to store the sorted results back in a file?
This code shows reordering the elements within an XDocument so that you can save it.
string xml = #"<Users>
<User>
<Address Name=""bbbb""/>
<Address Name=""aaaa"" />
</User>
<User>
<Address Name=""dddd""/>
<Address Name=""cccc"" />
</User>
</Users> ";
XDocument document = XDocument.Parse(xml);
var users = document.Root.Elements("User");
foreach (var user in users)
{
var elements = user.Elements("Address").OrderBy(a => a.Attribute("Name").Value).ToArray();
user.Elements().Remove();
user.Add(elements);
}
If you want an ordered in-memory model, then you can do it like this
var query = from user in document.Root.Elements("User")
select new
{
Addresses = from address in user.Elements("Address")
orderby address.Attribute("Name").Value
select new
{
Name = address.Attribute("Name").Value
}
};
foreach (var user in query)
{
foreach (var address in user.Addresses)
{
// do something with address.Name
}
}