Validate Presence of XML Element in a XML file - c#

I have a XML File as shown below ,
<?xml version="1.0"?>
<MainClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<Settings xsi:type="FileModel">
<Name>FileOne</Name>
<IsActive>true</IsActive>
<IsHidden>false</IsHidden>
</Settings>
<Settings xsi:type="FileModel">
<Name>FileTwo</Name>
<IsActive>true</IsActive>
<IsHidden>false</IsHidden>
</Settings>
<Settings xsi:type="ServerModel">
<Name>DelRep</Name>
<IsActive>false</IsActive>
<IsHidden>false</IsHidden>
</Settings>
</Items>
<DirectoryPath>D:\MainFolder</DirectoryPath>
</MainClass>
I am extracting some data using the Following code ,
XDocument File = XDocument.Load(path);
XElement element = File .Root.Elements().Single(x => x.Name == "DirectoryPath");
string usingPath = element.Value;
I have been trying to add a certain validation to the above code such that even in a situation that the xml file is missing the part <DirectoryPath>D:\MainFolder</DirectoryPath> , I would not get the error " sequence contains no matching element ".
Is there a property Similar to may be Path.Exist in C# to validate the presence of an XML element

You could use SingleOrDefault, which returns default value if the element is not found
XElement element = File .Root.Elements().SingleOrDefault(x => x.Name == "DirectoryPath");
if(element != null)
{
string usingPath = element.Value;
}

Use: SignleOrDefault. Then you will get proper XElement or null.

There is no default method to verify whether the given node exists or not.But we can use extension methods to achieve the same.
public static class XElementExtension
{
public static bool HasElement(this XElement xElement, string elementName)
{
return xElement.Elements(elementName).Any();
}
}
// Main
var xmlDocument = XElement.Load(#"TestFile.xml", LoadOptions.None);
string elementName = "DirectoryPath";
bool hasElement = xmlDocument.HasElement(elementName);
if(hasElement)
{
Console.WriteLine(xmlDocument.Elements(elementName).First().Value);
}

Related

Remove an item from XML file using C#

I'm trying to write and remove items (categories) that I've stored in an XML file. I've figured out how to add using new XElement and doc.Root.Add but I don't know how to remove and item that has the same title as the input.
XML:
<?xml version="1.0" encoding="utf-8"?>
<categories>
<category title="Horror"></category>
<category title="Romance"></category>
<category title="Health"></category>
<category title="SciFi"></category>
<category title="Programming" />
<category title="History" />
</categories>
C#:
public static void RemoveFromCategoryXMLFile(string title)
{
XmlDocument doc = new XmlDocument();
doc.Load("../../DAL/XML_Categories/Categories.xml");
XmlNode node = doc.SelectSingleNode($"/categories/category[#name='{title}']");
if (node != null)
{
XmlNode parent = node.ParentNode;
parent.RemoveChild(node);
doc.Save("../../DAL/XML_Categories/Categories.xml");
}
}
I want the item that matches the string title to be removed from the document. Right now nothing happens and it seems like the XmlNode returns null.
Using XDocument is recommended, as it is a newer class for parsing XML. With such class it's enought to use such code:
var title = "Horror";
var xml = XDocument.Load(#"path to XML");
xml.Root.Elements("category").Where(e => e.Attribute("title").Value == title).Remove();
xml.Save(#"path to output XML");

Obtain value stored within a set of attributes of a given type

I have the Following XML File , How can I obtain the value stored within the tags of a given type (In this Case say of type "FileModel")
.. How can I write some code which will get me the values Rep1 and Rep2 . I need these values to run a certain validation in a method
How can I achieve this ?
<?xml version="1.0"?>
<MainClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<Settings xsi:type="FileModel">
<Name>Rep1</Name>
<IsActive>true</IsActive>
<IsHidden>false</IsHidden>
</Settings>
<Settings xsi:type="FileModel">
<Name>Rep2</Name>
<IsActive>true</IsActive>
<IsHidden>false</IsHidden>
</Settings>
<Settings xsi:type="ServerModel">
<Name>DelRep</Name>
<IsActive>false</IsActive>
<IsHidden>false</IsHidden>
</Settings>
</Items>
</MainClass>
You can do this using XPath and a XmlNamespaceManager.
Example (.NetFiddle):
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
public class Program
{
public static void Main()
{
var doc = XDocument.Parse(XmlString);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
var names = doc.XPathSelectElements(
"/MainClass/Items/Settings[#xsi:type='FileModel']/Name",
namespaceManager
).Select(e => e.Value);
Console.WriteLine(String.Join(", ", names));
}
private static string XmlString = #"<?xml version=""1.0""?>
<MainClass xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<Items>
<Settings xsi:type=""FileModel"">
<Name>Rep1</Name>
<IsActive>true</IsActive>
<IsHidden>false</IsHidden>
</Settings>
<Settings xsi:type=""FileModel"">
<Name>Rep2</Name>
<IsActive>true</IsActive>
<IsHidden>false</IsHidden>
</Settings>
<Settings xsi:type=""ServerModel"">
<Name>DelRep</Name>
<IsActive>false</IsActive>
<IsHidden>false</IsHidden>
</Settings>
</Items>
</MainClass>";
}
Which will output: "Rep1, Rep2"
If you want to use System.Xml:
static void Main(string[] args)
{
List<string> result = new List<string>();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("myfile.xml");
XmlNodeList elemList = xmlDoc.GetElementsByTagName("Settings");
foreach (XmlNode node in elemList)
{
if(node.Attributes["xsi:type"].Value == "FileModel")
{
foreach (XmlNode item in node.ChildNodes)
{
if (item.Name == "Name")
result.Add(item.InnerText);
}
}
}
}
You can use linq to xml to achieve you desired result. Its more simple than you think. You don't need to have full knowledge of xml or linq.
To retrieve all Name within settings node with type is equal to FileModel.
Code:
var doc = XDocument.Load("Path to xml file");
//Or
var doc = XDocument.Parse(XmlString);
var ns = doc.Root.GetNamespaceOfPrefix("xsi");
var names = doc.Descendants("Items")
.Elements("Settings")
.Where(x => x.Attribute(ns + "type").Value == "FileModel")
.Select(x => x.Element("Name").Value)
.ToList();
names.ForEach(x => Console.WriteLine(x));
Output:
Or if you want your result in single string then you can join above list with comma(,) like,
var allName = string.Join(", ", names);
Console.WriteLine(allName);
Output:
Online Demo

How to get enclosure url with XElement C# Console

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
}

Before inserting new element in xml check if exists the value

I have below a xml file with the below format:
<?xml version="1.0" encoding="utf-8" ?>
<Root>
<Countries>
<country>India</country>
<country>USA</country>
<country>UK</country>
</Countries>
</Root>
string newCountry="UAE"
I want to insert this "UAE" country to the above xml file, before that I want to check whether "UAE" is already exists in the xml. If not exists then only want to insert otherwise no operation. How can I do this?
Like this:
XDocument xml = XDocument.Load("path_to_file");
string newCountry = "UAE";
XElement countries = xml.Descendants("Countries").First();
XElement el = countries.Elements().FirstOrDefault(x => x.Value == newCountry);
if (el == null)
{
el = new XElement("country");
el.Value = newCountry;
countries.Add(el);
}
//Console.WriteLine(countries.ToString());
The easiest way would probably be to read the xml into C# objects, check for the existance of UAE, potentially add it, and write the objects back to XML.

Read value from XML ignoring any namespaces

I have an XML file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="publisher" type="KP.Common.Util.XamlConfigurationSection, KP.Common"/>
</configSections>
<publisher>
<p:Publisher xmlns:p="http://schemas.KP.com/xaml/common/notification">
<p:KPLogSubscriber MinimumImportance="Information" />
<p:EventLogSubscriber MinimumImportance="Warning" Source="KPTTY" Log="Application" />
<p:DatabaseMailSubscriber xmlns="http://schemas.KP.com/xaml/data/ef" MinimumImportance="Error" ProfileName = "" Recipients = "administrator#firm.com" Subject = "KPTTY Error" />
</p:Publisher>
</publisher>
</configuration>
I am trying to read the value of the key Recipients using this code:
XmlDocument config = new XmlDocument();
config.Load(configPath);
XmlNode node = config.SelectSingleNode(#"/*[local-name() = 'configuration']/*[local-name() = 'publisher']/*[local-name() = 'Publisher']/*[local-name() = 'DatabaseMailSubscriber']/#Recipients");
Console.WriteLine(node.Value);
but I get an exception (node is null). Is there something wrong with my Xpath? I am trying to ignore any namespaces that might not be present in the xml.
If it is OK to use Linq2Xml
XDocument xDoc = XDocument.Load(fname);
var recipients = xDoc.Descendants()
.First(d => d.Name.LocalName == "DatabaseMailSubscriber")
.Attribute("Recipients")
.Value;
You forgot to do local-name for "Recipients". "Recipients" attribute have empty prefix meaning its namespace is xmlns="http://schemas.KP.com/xaml/data/ef" as defined on the "DatabaseMailSubscriber" element.
I.e. if you don't care of path you can simple use "//" for "any child:
"//*[local-name() = 'DatabaseMailSubscriber']/#*[local-name() = 'Recipients]"
Note: consider actually using namespace properly... or use XDocument as suggested by L.B.

Categories

Resources