How to remove null valued child nodes in Xml using c# - c#

I have an XML Documnet consisting parent nodes and child nodes,
<?xml version='1.0' encoding='UTF-8'?>
<response>
<system_timestamp>2016-10-21 13:40:28</system_timestamp>
<response_data>
<status>Active</status>
<profile>
<first_name>John</first_name>
<last_name>Abraham</last_name>
<ship_to_address>
<address_1>null</address_1>
<address_2>null</address_2>
<city>null</city>
<state>null</state>
<postal_code>null</postal_code>
</ship_to_address>
</profile>
</response_data>
</response>
I am having few null valued child nodes like <address_1> and <address_2>. So, now how would I remove those null values of my child nodes. I tried
doc.Descendants().Where(e => string.IsNullOrEmpty(e.Value)).Remove();
But this is not working . And i am using this
XmlDocument doc = new XmlDocument();
doc.LoadXml(_value);
code to parse xml document. Do we have any other methods to remove using XMLDocument instead of XElement.

e.Value isn't a null reference or an empty string - it's the string "null" because that's the value in your element.
You want:
doc.Descendants().Where(e => (string) e == "null").Remove();

When removing an item from a list you must removed from last item to first item otherwise the indexing gets screwed up and not all the items get removed. Try this
sing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<XElement> nulls = doc.Descendants().Where(x => (string)x == "null").ToList();
for (int i = nulls.Count - 1; i >= 0; i--)
{
nulls[i].Remove();
}
}
}
}

Related

Replacing XML innerText with XMLElement or XElement

//I would like to get some advice on how to replace the node value of a element in XML using XMLElement or XElement. Right now I'm trying it with XMLElement but the compiler gives me only errors or the XML replace the whole document insted of selected node. I have a XML/XSD sample that I need to fill with data and create like 500 XML a day but I cant insert the data into the right elements.
I expect that I can replace / insert data into the element value. Like I want to change the City text value. I have a table with content and based on the filled data I need to add it into specific XML elements and save.
As for now every sample code I found and some I covered up did give compile errors / null reference object( at assigning InnerText) or deleted all the elements and added just one line with my text value.
Te code below gives me ''Object reference not set to an instance of an object.'
' at .InnerText. Actually the declatarion of SelectSingleNode("ID") return me also a null.
-<Receiver>
-<ID>
<RNumber>9999999999</RNumber>
<Name>ABC AGD sp. z o. o.</Name>
</ID>
-<Address>
-<AddressSpec>
<Country>PL</Country>
<Street>Kwiatowa</Street>
<HouseNum>1</HouseNum>
<City>Warszawa</City>
</AddressSpec>
</Address>
<Email>test#test.pl</Email>
<Phone>667444555</Phone>
</ID>
-</Receiver>
using System.IO;
using System.Net;
using System.Xml;
using System.Xml.Linq;
class ReplaceXMLData
{
public static void Main(Args _args)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(//path/sample.xml);
System.Xml.XmlElement root = doc.DocumentElement;
System.Xml.XmlElement Street = doc.SelectSingleNode("Street");
Street.innertext = "random";
doc.AppendChild(root);
doc.Save(path);
info("Details added Successfully");
}}
Here is solution using Xml Linq (XDocument). You need to use Decendants with FirstOrDefault
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication15
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement id = doc.Descendants("ID").FirstOrDefault();
}
}
}

How to filter data from xml using xmldocument class & xpath

I have xml stored in string variable. from that xml I need to filter data based on StandardValue. I want to extract only those records whose StandardValue is not null & not empty. I tried but my code did not work.
string xmldoc= #"<?xml version=""1.0"" encoding=""utf-8""?>
<TickerBrokerStandardDateLineitem>
<Ticker />
<TickerID />
<TickerBrokerStandardDateLineitemValues>
<TickerBrokerStandardDateLineitemValue>
<TabName>Consensus Model</TabName>
<StandardDate>1Q 2010</StandardDate>
<BRTab>Income Statement</BRTab>
<BRLineItem>NET REVENUES</BRLineItem>
<Action>Extracted</Action>
<StandardLineItem>Net Revenue</StandardLineItem>
<StandardValue>329.623</StandardValue>
</TickerBrokerStandardDateLineitemValue>
<TickerBrokerStandardDateLineitemValue>
<TabName>Consensus Model</TabName>
<StandardDate>2Q 2010</StandardDate>
<BRTab>Income Statement</BRTab>
<BRLineItem>NET REVENUES</BRLineItem>
<Action>Extracted</Action>
<StandardLineItem>Net Revenue</StandardLineItem>
<StandardValue></StandardValue>
</TickerBrokerStandardDateLineitemValue>
<TickerBrokerStandardDateLineitemValue>
<TabName>Consensus Model</TabName>
<StandardDate>2Q 2010</StandardDate>
<BRTab>Income Statement</BRTab>
<BRLineItem>NET REVENUES</BRLineItem>
<Action>Extracted</Action>
<StandardLineItem>Net Revenue</StandardLineItem>
<StandardValue/>
</TickerBrokerStandardDateLineitemValue>
</TickerBrokerStandardDateLineitemValues>
</TickerBrokerStandardDateLineitem>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmldoc);
XmlNodeList nodeList = doc.GetElementsByTagName("TickerBrokerStandardDateLineitemValue");
List<string> list = new List<string>();
foreach (XmlNode item in nodeList)
{
foreach (XmlElement i in item)
{
if (i.Name == "StandardValue")
{
if (i.InnerText == string.Empty)
{
list.Add(item.OuterXml);
}
}
}
}
string a = string.Empty;
foreach (var item in list)
{
a = doc.InnerXml.Replace(item, "");
}
string str1 = doc.OuterXml;
My above code does not work. basically how to filter with xpath that return only those records whose StandardValue is not null & not empty.
How to achieve it with XmlDocument class instead of xdocument.
At end I have to stored filtered record's xml into string. I know XmlDocument class has outer xml property which return full xml.
Give me sample code which will return filter records & stored filter records xml into string.
Use xml linq which is the newer version of the Net xml library :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
XDocument doc = XDocument.Parse(xml);
List<XElement> tickerBrokerStandardDateLineitemValues = doc.Descendants("TickerBrokerStandardDateLineitemValue")
.Where(x => (x.Element("StandardValue") != null) && ((string)x.Element("StandardValue") != string.Empty))
.ToList();
}
}
}
Assuming the input string your provided in the question.
This will select all TickerBrokerStandardDateLineitemValue values that has StandardValue element and it's not empty or white space (normalize-space).
normalize-space:
strips leading and trailing white-space from a string, replaces
sequences of whitespace characters by a single space, and returns the
resulting string.
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlStr); // <input from the question>
var nodes = xmlDoc.SelectNodes("//TickerBrokerStandardDateLineitemValue[StandardValue and string-length(normalize-space(StandardValue))]");

c# - how to get child element val where another child element equals to a val

I'm trying to get a child element's value where another child element value equals to a value,
for example I have this xml file:
<CATALOG>
<game>
<name>Assassins Creed Origins</name>
<picture>pic1</picture>
<torrent>file1</torrent>
</game>
<game>
<name>mylifeisdone</name>
<picture>pic2</picture>
<torrent>file2</torrent>
</game>
</CATALOG>
I want to get picture value where name equals to mylifeisdone
Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<XElement> games = doc.Descendants("game").ToList();
string picture = games.Where(x => (string)x.Element("name") == "mylifeisdone").Select(x => (string)x.Element("picture")).FirstOrDefault();
}
}
}
The easiest way I could think of is using XDocument:
XDocument doc = XDocument.Parse(#"
<CATALOG>
<game>
<name>Assassins Creed Origins</name>
<picture>pic1</picture>
<torrent>file1</torrent>
</game>
<game>
<name>mylifeisdone</name>
<picture>pic2</picture>
<torrent>file2</torrent>
</game>
</CATALOG>");
var picture = doc.Descendants("game")
.First(g => g.Element("name").Value == "mylifeisdone")
.Element("picture").Value;
This first gets all elements "game" and searches for the first element, of which the name element has the value "mylifeisdone"; after that, it retrieves the value of the "picture" element.
Note: you may need the namespace System.Xml.Linq and, if you are reading the XML from a file, use XDocument.Load("path").

Get Just 3rd level XML nodes' names LINQ C#

I'm trying to get the 3rd level names from a XML.
I found this but it gives me also the 4th level, which i don't want.
How should i do it?
XDocument xdoc = XDocument.Load(path + #"\Pages\Results\Target_XML.xml");
foreach (var name in xdoc.Root.Element("Veg").DescendantNodesAndSelf().OfType<XElement>().Select(x => x.Name).Distinct())
{
Console.WriteLine(name);
}
Example (I want just the Tom and Car as strings, without Name and Cal) -
This is the XML:
<DEV>
<Veg>
<Tom>
<Name>aa</Name>
<Cal>99</Cal>
</Tom>
<Car>
<Name>aa</Name>
<Cal>99</Cal>
</Car>
</Veg>
<Fru>
<Ban>
<Name>aa</Name>
<Cal>99</Cal>
</Ban>
</Fru>
</DEV>
Using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Runtime.InteropServices;
namespace ConsoleApplication23
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<string> strings = doc.Elements().Elements().Elements().Select(x => x.Name.LocalName).ToList();
}
}
}
You can reference the child nodes with XElement's ChildNodes property. Like this:
XmlNodeList childNodes = xdoc.Root.Element("Veg").ChildNodes;
In this case, the childNodes list would contain the 3rd level nodes you want.
var l_RootElement = XElement.Load(path + #"\Pages\Results\Target_XML.xml");
foreach (var l_VegElement in l_RootElement.Elements("Veg").Elements()) {
Console.WriteLine(l_VegElement.Name);
}

How can I remove any footnote or notes or end notes in my Xpathselectelement

I have an html that contains this value
<h3 class="sgc-5">Blah blah<sup class="fn-num"><a id="r_fn1" href="#fn1">1</a></sup></h3>
for me to get the value of the h3, I used the code below
XDocument xDoc = XDocument.Parse(xml);
Console.WriteLine(xDoc.XPathSelectElement("//h3").Value)
and I get the result Blah Blah1, but the result what I want is Blah Blah only I want to remove 1 in the result, I try .Remove() to remove the 1 in the end of Blah blah, but this is not safe, as it will remove all the end of the h3.Value that contains 1, Can anyone show me how to not include the value <sup class="fn-num"> in the xDoc.XPathSelectElement("//h3").Value in my case.
Try this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Xml;
namespace Test
{
class Program
{
static int Main(string[] args)
{
String xml = "<h3>Blah blah<sup><a>1</a></sup></h3>";
XDocument xDoc = XDocument.Parse(xml);
var h3 = xDoc.XPathSelectElement("//h3");
String tmp = h3.DescendantNodes().Where(node=>node.NodeType == XmlNodeType.Text).First().ToString();
Console.WriteLine(tmp);
return 1;
}
}
}
Here I know it's the first node. You can loop thru children nodes and check for node type you want.
Here is a link to all node types: https://msdn.microsoft.com/en-us/library/system.xml.xmlnodetype(v=vs.110).aspx
The value Blah blah you want to get from the h3 element is among other nodes and it is an instance of the XText type. In order to get this value, you could select the first node of the XText type. It contains the string you are looking for:
string value = xDoc.XPathSelectElement("//h3").Nodes().OfType<XText>().First().Value;
If you want to find the first text node among all descendants of the node then the DescendantNodes method should be used instead of the Nodes method.
var node = xDoc.XPathSelectElement("//h3").DescendantNodes().OfType<XText>().FirstOrDefault();
if (node != null)
{
string value = node.Value;
}

Categories