How to delete nodes from XML with exact string match in c# - c#

I have below xml. I want to delete those nodes which doesn't contains attributes. in below xml I want to delete last 4 nodes which doesn't have attributes.
XML
<products>
<product system="kn-movies" code="UR">Unrated</product>
<product system="mu-movies" code="UR">Unrated</product>
<product system="na-movies" code="UR">Unrated</product>
<product system="fj-movies" code="UR">Unrated</product>
<product>Unrated (Unrated )</product>
<product>Unrated (Unrated )</product>
<product>Unrated (Без классификации )</product>
<product>Unrated (غير مصنف )</product>
</products>
I had tried this c# code
var ratingNode = document.Descendants("rating").Where(t => t != null && t.Equals(Convert.ToString(nodeItem))).FirstOrDefault();
if (ratingNode != null)
{
ratingNode.Remove();
}
but it doesn't worked for me. please help me out where i m doing mistakes.

System.Xml.Linq.XDocument doc = System.Xml.Linq.XDocument.Load(filepath);
var newList = doc.Root.Descendants().ToList().RemoveAll(x => x.Attributes() == null || x.Attributes().Count() <= 0);
Hope it helps!!

Hope this will do trick
XmlNodeList nodes = xmlDocument.GetElementsByTagName("products");
foreach(XmlNode node in nodes)
{
if(node.Attributes.Count == 0)
{
node.RemoveAll;
}
}

You could use Linq to Xml and query for elements which has no attributes, then you just need Remove call to remove those elements.
XDocument doc = XDocument.Load(filepath);
doc.Root
.Descendants() // flattens the structure
.Where(x=> x.Attributes().Count() <= 0) // filter elements which has no attributes
.Remove(); // Remove them
Check this Demo

Related

Change Value of nested node

This seems like a simple question but I can't seem to get started on a working solution. The final goal is to change the value of the ConstantValue element highlighted below. My strategy is to find the Component node and drill down from there. The problem is that keep returning a null and I'm not sure why. Below is the code I'm using a the xml I'm using. Any hints would be great.
XDocument xmlDoc = XDocument.Parse(str);
var items = xmlDoc.Descendants("Component")
.Where(x => x.Attribute("Name").Value == "axesInterface")
.FirstOrDefault();
<?xml version="1.0" encoding="utf-8"?>
<Document>
<Engineering version="V17" />
<DocumentInfo>
</DocumentInfo>
<SW.Blocks.FB ID="0">
<AttributeList>
<Interface><Sections></Sections></Interface>
<MemoryLayout>Optimized</MemoryLayout>
<MemoryReserve>100</MemoryReserve>
<Name>EM00_CM01_Warp1</Name>
<Number>31650</Number>
<ProgrammingLanguage>LAD</ProgrammingLanguage>
<SetENOAutomatically>false</SetENOAutomatically>
</AttributeList>
<ObjectList>
<SW.Blocks.CompileUnit ID="4" CompositionName="CompileUnits">
<AttributeList>
<NetworkSource>
<FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
<Parts>
<Access Scope="GlobalVariable" UId="27">
<Symbol>
<Component Name="HMIAxisCtrl_Interface" />
<Component Name="axesInterface" AccessModifier="Array">
<Access Scope="LiteralConstant">
<Constant>
<ConstantType>DInt</ConstantType>
<ConstantValue>0</ConstantValue>
</Constant>
</Access>
</Component>
</Symbol>
</Access>
</Parts>
</FlgNet>
</NetworkSource>
</AttributeList>
</SW.Blocks.CompileUnit>
</ObjectList>
</SW.Blocks.FB>
</Document>
You can use XQuery to get the correct node:
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
//
var nm = new XmlNamespaceManager(new NameTable());
nm.AddNamespace("sm", "http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4");
var node = xdoc.XPathSelectElement(#"//sm:Access[#Scope=""LiteralConstant""]/sm:Constant/sm:ConstantValue", nm);
node.Value = "Something Else";
dotnetfiddle
For multiple nodes, change XPathSelectElement to XPathSelectElements
On your XML example, you can simply get specified node with this piece of code at any depth:
XDocument xmlDoc = XDocument.Parse(str);
XElement node = xmlDoc.Descendants().FirstOrDefault(x => x.Name.LocalName == "ConstantValue");
node.Value = "New value";
xmlDoc.Save(somewhere);
If there may be multiple nodes with "ConstantValue" name - then just replace FirstOrDefault with Where and work with filtered by names IEnumerable<XElement>.
Why it isn't find by x.Name == "ConstantValue":
EDIT: added samples.
// That's your parent node
var componentNode = xmlDoc.Descendants()
.Where(x => x.Name.LocalName == "Component"
&& (string)x.Attribute("Name") == "axesInterface");
// Get first ConstantValue node from parent Component node
var constantValueNode = componentNode.Descendants()
.FirstOrDefault(x => x.Name.LocalName == "ConstantValue");
// or get all ConstantValue nodes from parent Component node
var constantValueNodes = componentNode.Descendants()
.Where(x => x.Name.LocalName == "ConstantValue");
if (constantValueNode is XElement)
constantValueNode.Value = "New value";
You can create extension method to get parent node by specifying level:
public static class Extensions
{
public static XElement GetParentNode(this XElement element, int parentLevel)
{
XElement node = element.Parent;
for (int i = 0; i < parentLevel; i++)
node = node.Parent;
return node;
}
}
In your example, var parent = constantValueNode.GetParentNode(2); will return Component node (with attribute Name="axesInterface"). var parent = constantValueNode.GetParentNode(12); will return root "Document" node.

Use C# to loop through XML document and if condition is met replace value or node

I have a XDocument with XML XDocument xdoc1 = XDocument.Load(doc1)
I want to to loop through XML document and if condition is met replace value or node.
I tried code like:
var list = from item in xdoc1.Root.Element("New").Elements() select item;
foreach (XElement item in list)
{
foreach (var node in item.Nodes())
{
if (node.ToString() == "DIV||<Control>")
{
item.Element("Value").Value = "DIV||TextBox";
}
}
But it does not work for me.
If my XML looks like this
<Test>
<New>
<DoSometing>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometing>
<DoSometingElse>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometingElse>
</New>
</Test>
So my idea is to loop through all the xml and if the condition == <Control> then replace it.
I also tried suff like IEnumerable<XElement> list = from item in xdoc1.Root.Element("New").Elements() where (item.Name == "Value") select item;
You might consider filtering the elements in the query block, and only applying updates to the elements that are necessary. Note that the XElement.Value is being used here, so the decoded element value has to be used.
var list = from item in xdoc1.Root.Element("New").Elements().Elements("Value")
where item.Value == "DIV||<Control>"
select item;
foreach (XElement item in list)
{
item.Value = "DIV||TextBox";
}
Somewhat simpler version.
c#
void Main()
{
const string fileName = #"e:\temp\hala.xml";
const string searchFor = "DIV||<Control>";
const string replaceWith = "789";
//XDocument xdoc = XDocument.Load(fileName);
XDocument xdoc = XDocument.Parse(#" < Test >
<New>
<DoSometing>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometing>
<DoSometingElse>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometingElse>
</New>
</Test>");
// step #1: find element(s) based on the search value
var xmlFragment = xdoc.Descendants("Value")
.Where(d => d.Value.Equals(searchFor));
// step #2: if found, set its value
foreach (XElement element in xmlFragment)
{
element.SetValue(replaceWith);
}
}

C# XML get nodes based on attribute

I have the following xml:
<root ...>
<Tables>
<Table content="..">
</Table>
<Table content="interesting">
<Item ...></Item>
<Item ...></Item>
<Item ...></Item>
</Table>
...etc...
</Tables>
</root>
I'm using the following code to get the items from the 'interesting' node:
XElement xel = XElement.Parse(resp);
var nodes = from n in xel.Elements("Tables").Elements("Table")
where n.Attribute("content").Value == "interesting"
select n;
var items = from i in nodes.Elements()
select i;
Is there a simpler, cleaner way to achieve this?
Well there's no point in using a query expression for items, and you can wrap the whole thing up very easily in a single statement. I wouldn't even bother with a query expression for that:
var items = XElement.Parse(resp)
.Elements("Tables")
.Elements("Table")
.Where(n => n.Attribute("content").Value == "interesting")
.Elements();
Note that this (and your current query) will throw an exception for any Table element without a content attribute. If you'd rather just skip it, you can use:
.Where(n => (string) n.Attribute("content") == "interesting")
instead.
You can use XPath (extension is in System.Xml.XPath namespace) to select all items in one line:
var items = xel.XPathSelectElements("//Table[#content='interesting']/Item");
If you don't need nodes outside of your query for items, you can just do this:
var items = from n in xel.Elements("Tables").Elements("Table")
where n.Attribute("content").Value == "interesting"
from i in n.Elements()
select i;
using xml document
XmlDocument xdoc = new XmlDocument();
var item= xdoc.GetElementsByTagName("Table[#content='interesting']/Item");

how to check xmlnode for innertext or value in c#?

I created xmlnodelist and i want to handle the value of elements that dont have childs.
at the following code i'm checking for childnodes and i get true from all of the elements, even
those without childs.
how can i pick the last elements in the tree and handle the value's?
XmlDocument XDoc = new XmlDocument();
XDoc.Load("d://avi.xml");
XmlNodeList XList = XDoc.SelectNodes("//*");
foreach (XmlElement XNode in XList)
{
if (XNode.HasChildNodes == true)
{
Console.WriteLine("this node has childs");
continue;
}
else Console.WriteLine("this node dont have childs");
}
<level1>
<level2>
<level3>header3</level3>
<level4>another</level4>
<level31>header31</level31>
</level2>
<level2>
<level3>111</level3>
<level31>nn</level31>
</level2>
</level1>
How about using Linq to Xml for this?
var xElem = XElement.Parse(xml);
var leafElements = xElem.Descendants()
.Where(e => !e.HasElements)
.ToList();
The text within an element is a "node" as well. What you want is
if (XNode.ChildNodes.Any(n=>n.NodeType == XmlNodeType.Element))
Alternatively you can loop through the ChildNodes and see if one of them is an element.

Parsing data from a child element in an xml document

I'm having difficulty parsing a sub element from an xml document.
The document contains a series of elements containing pricing information that I need to extract the Euro price from. No matter what I do, I can't seem to extract the data that I need. The result is always null.
<departure>
<pricing xmlns="http://website.com/api/feeds/xmlns/20110926/">
<price age_group="Adult" label="1 Adult" max_age="100" max_passengers="100" min_age="12" min_passengers="1">
<USD>4249.00</USD>
<AUD>4299.00</AUD>
<CHF>3649.00</CHF>
<GBP>2749.00</GBP>
<NZD>5399.00</NZD>
<CAD>4399.00</CAD>
<EUR>3249.00</EUR> <------------this is what I need to parse
</price>
</pricing>
<pricing xmlns="http://website.com/api/feeds/xmlns/20110926/">
<price age_group="Adult" label="1 Adult" max_age="100" max_passengers="100" min_age="12" min_passengers="1">
<USD>4249.00</USD>
<AUD>4299.00</AUD>
<CHF>3649.00</CHF>
<GBP>2749.00</GBP>
<NZD>5399.00</NZD>
<CAD>4399.00</CAD>
<EUR>3249.00</EUR> <------------this is what I need to parse
</price>
</pricing>
<departure>
XmlNodeList departureNodes = xmlDoc.GetElementsByTagName("departure");
if (departureNodes.Count > 0)
{
foreach (XmlElement element in departureNodes)
{
string priceInEUR = xmlElement.SelectSingleNode("pricing/price/EUR"); // returns null
string priceInEUR2 = xmlElement.SelectSingleNode("//pricing/price/EUR"); // also returns null
}
}
I recommend to use XDocument and Linq to XML.
using System.Xml.Linq;
IEnumerable<XElement> prices = from t in doc.Root.Descendants("EUR");
foreach (XElement t in prices)
{
string priceInEUR = t.Value;
}
The way I have this document here: http://searisen.com/xmllib/extensions.wiki
You can currently do: (presuming departure is a child of the root node)
decimal[] euros = XElement.Load(xmlFile)
.GetEnumerable("departure/pricing",
x => x.Get("price/EUR", decimal.MinValue))
.ToArray();
This gets all the euros, the two you have listed.

Categories