How to get nodes where his child node has some value - c#

I have below xml structure:
<?xml version="1.0" encoding="UTF-8" ?>
<rss>
<channel>
<item>
<title>Some Title</title>
</wp:comment>
<wp:comment_approved><![CDATA[1]]></wp:comment_approved>
</wp:comment>
</wp:comment>
<wp:comment_approved><![CDATA[1]]></wp:comment_approved>
</wp:comment>
</item>
</channel>
</rss>
I can easily get all wp:comments by:
xmlNode.SelectNodes("*[name()='wp:comment']")
But how can I get all wp:comments where wp:comment_approved has value 1?

it's updated #Stefan Hegny answer, as you need not comment_approvedelement, but wp:comment
xmlNode.SelectNodes("//*[name()='wp:comment'][./*[local-name() = 'comment_approved' and . = '1']")
i'm not sure if default css locators working here, but in common css xPath i'll use this locator (logic is simple - you seach some element, that contains element with special parameter, so you can adjust this locator to your needs):
//someTag[./innerTag[text() = '1']]

Related

Edit an XML file without rewriting using XmlSerializer in C#

I have an XML file eg:
<?xml version="1.0" encoding="utf-8"?>
<items>
<item>
<id>1</id>
<details></details>
<description></description>
</item>
<item>
<id>2</id>
<details>
</details>
<description></description>
</item>
</items>
Now say suppose I want to modify an XML file such that I want to add some data to details tag for item with id=2. Using XML serializer, I would have to read the whole XML file then select item with item Id 2 and modify that class object and write whole file again? So for every update I would have to read the whole xml file into memory, then edit it in memory and then re-write as a whole to the disk?
Is there any other way to achieve this? Like could I have alogic which would simply update the node to the existing XML file?

How to use LINQ to get data from an XML file?

I have xml files which look like this:
<?xml version="1.0" encoding="utf-8"?>
<record id="177" restricted="false">
<type>record type</type>
<startdate>2000-10-10</startdate>
<enddate>2014-02-01</enddate>
<titles>
<title xml:lang="en" type="main">Main title</title>
<!-- only one title element with type main -->
<title xml:lang="de" type="official">German title</title>
<!-- can have more titles of type official -->
</titles>
<description>description of the record</description>
<categories>
<category id="122">
<name>category name</name>
<description>category description</description>
</category>
<!-- can have more categories -->
</categories>
<tags>
<tag id="5434">
<name>tag name</name>
<description>tag description</description>
</tag>
<!-- can have more tags -->
</tags>
</record>
How do I select the data from these xml files using LINQ, or should I use something else?
You can load xml into XDocument objects using either the Load() method
for files, or the Parse() method for strings:
var doc = XDocument.Load("your-file.xml");
// OR
var doc = XDocument.Parse(yourXmlString);
Then you can access the data using LINQ:
var titles =
from title in doc.XPathSelectElements("//title")
where title.Attribute("type").Value == "official"
select title.Value;
Was searching for examples of Xmlserializer and found this: How to Deserialize XML document
So why not to try. I did Ctrl+C and Edit -> Paste Special -> Paste XML As Classes in Visual Studio 2013 and... Whoa I got all the classes generated. One condition target framework must be 4.5 and this function is available from Visual Studio 2012+ (as stated in that post)

XPath accessing a non-uniform XML file

I have an XML file that's modeled something like the following:
<data>
<customer>
<id></id>
<name></name>
<model>
<id></id>
<name></name>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
</model>
<model>
<id></id>
<name></name>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
</model>
</customer>
<customer>
<id></id>
<name></name>
<model>
<id></id>
<name></name>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
</model>
</customer>
<customer>
<id></id>
<name></name>
</customer>
</data>
Using XPath in C#, I need to access the following for each customer:
customer/id
customer/name
customer/model/id
customer/model/name
customer/model/item/id
customer/model/item/history/date
customer/model/item/history/location
When data does not exist for any given customer, then the result stored will be null, since all fields of my customer object must be populated. If the XML file was uniform, this would be easy. My problem is accessing each customer's data when each customer may potentially have a different number of model and item nodes. Any ideas?
Assuming that the result will consist of these types of object:
Customer, Model, Item and History
The pseudo - code for populating them is:
Select all /data/customer elements
For each of the nodes selected in 1. do:
Select ./id and ./name and populate the corresponding properties of the object.
Populate a List<Model> property from all model children of the current customer element:
Select all ./model children of the current element.
For each selected model element in 5. create a Model object and populate its properties:
For the current Model object populate its Id and Name properties by selecting the ./id and ./name children of the current model element.
Populate a List<Item> property from all item children of the current model element:
Select all ./item children of the current element.
For the current Item object populate its Id property by selecting the ./id child of the current item element.
In a similar way populate the History property of the Item object with a History object, that you create and populate from the ./history child of the current item element.
Of course, you can skip all this if you use XML Serialization -- read about this here: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

Xml generated with fields & attributes entered by webform

i have the following problem!
I need to generate an Xml Document in asp.net. For this, i need to enter the following information:
- Number of tags.
- Name of each tags (example: , , , etc).
- Attributes of each tag (example: Alex... etc)..
I have already this function that received a List (TAGLIST) with the name of the xml tags.
public void functionxml()
{
string RutaSave = string.Format(#"C:\xml.xml");
var Serializer = new XmlSerializer(typeof(List<string>));
TextWriter textWriter = new StreamWriter(RutaSave);
Serializer.Serialize(textWriter, TagsList);
}
But the xml generated by this function looks like this:
<?xml version="1.0" encoding="utf-8"?>
<dictionary>
<item>
<key>
<string>CAMPO1</string>
</key>
<value>
<anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:string" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">test</anyType>
</value>
</item>
<item>
<key>
<string>CAMPO2</string>
</key>
<value>
<anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:int" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">2</anyType>
</value>
</item>
</dictionary>
Please, any help will be welcome!
Thanks in advance.
You should use XMLWriter instead of XMLSerializer. XMLSerializer tries to produce a XML file for an object; some kind of serialization. It is more like a BinarySerializer but it produces XML format instead of byte arrays or streams. XMLWriter is a class which writes a hierarchy into a XML file.

Reading different XML with C#/DOM

I am currently using DOM to navigate xml in my C# project. However, some XML that i've come across lately is a bit different.
whereas usually I have:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<entry>
<author>
<name>Me =)</name>
</author>
<content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</content>
</entry>
</feed>
and can navigate using foreach entry as entry, selectsinglenode(/content/somefield1/subfield), innertext to get the data from the subfield for each entry, the new XML looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:entry>
<atom:author>
<name>Me =)</name>
</atom:author>
<atom:content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</atom:content>
</atom:entry>
</atom:feed>
selectsinglenode(/atom:content/somefield1/subfield) is definitely not going to work...any suggestions?
atom: is just the namespace, and possibly you might just ignore it. If it still not works, you may have to use:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
selectsinglenode("atom:content/somefield1/subfield", nsmgr);
Which is documented here

Categories

Resources