if exist on an XML node in XmlNodeList C# - c#

How can i check if a node exists in an XmlNodeList? I have populated a list, and i need to query out specific values. this is how I am doing that.
var xList = xelRoot.SelectNodes("aaa/bbb/ccc/ddd/eee/fff/ggg/hhh");
foreach (XmlNode node in xList)
{
serviceVal = node["service"].InnerText.ToString();
}
there are cases where the service node does not exist. and when that happens I get the error "Object reference is not set to instance of an object".
is there a way to return a string value if the node does not exist?
here is a sample of the xml. notice that rule 1 does not have a service node
<entry name="aaa">
<from>any</from>
<to>any</to>
<source>any</source>
<destination>any</destination>
<source-user>any</source-user>
<category>any</category>
<service>any</service>
</entry>
<entry name="Rule 1">
<from>any</from>
<to>any</to>
<source>any</source>
<destination>any</destination>
<source-user>any</source-user>
<category>any</category>
</entry>

Simply test for null...
XmlNode subNode;
foreach (XmlNode node in xList)
{
subNode = node["service"];
if (subNode != null)
{
serviceVal = subNode.InnerText;
}
else
{
serviceVal = string.Empty;
}
}

Related

How to get "elements" in node

I trying to get "elements" from node and show in MessageBox
My XML: <Item Name="Test" Count="5"/>
Elements:
Name
Count
My Code:
XmlNodeList xmlNodes = xmlDocument.SelectNodes("Item");
foreach (XmlNode xmlNode in xmlNodes)
{
MessageBox.Show(xmlNode.InnerText);
}
But I do not know how to do this
You need to use Attributes. Check my solution
XmlNodeList xmlNodes = xmlDocument.SelectNodes("Item");
foreach (XmlNode xmlNode in xmlNodes)
{
foreach (XmlAttribute attr in xmlNodes.Attributes)
{
MessageBox.Show($"Attribute Name is {attr.Name} and Value is {attr.Value}");
}
}

read child nodes xml

Here is my xml which i am trying to read.
<VacancyList xmlns="urn:abc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" generated="2016-04-20T11:42:47" xsi:schemaLocation="http://www.abc.in/dtd/vacancy-list.xsd">
<Vacancy id="1619993" date_start="2016-04-15" date_end="2016-04-22" reference_number="">
<Versions>
<Version language="nb">
<Title>Marketing Specialist</Title>
<TitleHeading/>
<Location>CXCXC</Location>
<Engagement/>
<DailyHours/>
<Region>
<County id="11">sds</County>
<County id="1">zxzx</County>
</Country>
</Region>
<Categories>
<Item type="position-type" id="3909">sER</Item>
<Item type="duration" id="contract">ss</Item>
<Item type="extent" id="fulltime">sd</Item>
<Item type="operating-time" id="day">s</Item>
</Categories>
</Version>
</Versions>
</Vacancy>
</VacancyList>
I want to read node location so wrote below code
XmlDocument xd = new XmlDocument();
xd.Load("https://abc.in/list.xml");
XmlNamespaceManager ns = new XmlNamespaceManager(xd.NameTable);
ns.AddNamespace("msbld", "urn:abc");
XmlNodeList nodelist = xd.SelectNodes("//msbld:VacancyList", ns);
if (nodelist != null)
foreach (XmlNode node in nodelist)
{
XmlNode nodelist1 = node.SelectSingleNode("Vacancy");
if (nodelist1 != null)
foreach (XmlNode node1 in nodelist1)
{
var k = node1.Attributes.GetNamedItem("Location").Value;
}
}
But i dont get anything in variable "node1". How to fix this?
Also is there any better solution for this?
Update1
i modified code but i only get node Title. cant get others inside Version node like Location.
if (nodelist != null)
foreach (XmlNode node in nodelist)
{
XmlNode nodelist1 = node.SelectSingleNode("//msbld:Vacancy/msbld:Versions",ns);
if (nodelist1 != null) {
XmlNode nodelist2 = nodelist1.SelectSingleNode("//msbld:Version", ns);
foreach (XmlNode node3Node in nodelist2)
{
var k = node3Node.Attributes.GetNamedItem("Location").Value;
}
}
}
xmlns="urn:abc" is a default namespace. Notice that descendant elements without prefix inherits ancestor's default namespace implicitly. You need to use the same prefix that references default namespace URI for acessing Vacancy and Location as well :
XmlNode nodelist1 = node.SelectSingleNode("msbld:Vacancy", ns);
Your updated code introduces an entirely different problem; / at the beginning of a path expression will always reference document element, unless you explicitly set the context to current active context by using . before /, for example :
XmlNode nodelist1 = node.SelectSingleNode(".//msbld:Vacancy/msbld:Versions",ns);
If you only need the Location element then you can do it like this:
var doc = XElement.Load("path/to/file");
var location = doc.Descendants
.FirstOrDefault(e => e.Name.LocalName == "Location"));

how to parsing XML file

I have a file in that format
<?xml version="1.0" encoding="UTF-8"?>
<AMG>
<Include File="..."/> <!-- comment -->
<Include File="...."/> <!-- comment -->
<AMGmers Name="Auto">
<Array Type="move" Name="move_name"/>
</AMGmers>
<AMGmers Name="Black" Parent="Auto">
<Attr Type="Color" Name="auto_Params"/>
</AMGmers>
<!-- comment -->
</AMG>
I have to get all name from <AMGmers>, and I have to check availability Parent.
I was trying to do so
XmlDocument doc1 = new XmlDocument();
doc1.Load("test.xml");
XmlNodeList elemList1 = doc1.GetElementsByTagName("Name");
Please help me understand.
Since <AMG> is the root node and <AMGmers> tags are inside <AMG>, you can get all <AMGmers> tags using this syntax
XmlNodeList elemList1 = doc1.SelectNodes("AMG/AMGmers");
I assume you want to get the value of Name attribute from all <AMGmers> tags and check whether each <AMGmers> tag has Parent attribute, so this code should work
foreach (XmlNode node in elemList1)
{
if (node.Attributes["Name"] != null)
{
string name = node.Attributes["Name"].Value;
// do whatever you want with name
}
if (node.Attributes["Parent"] != null)
{
// logic when Parent attribute is present
// node.Attributes["Parent"].Value is the value of Parent attribute
}
else
{
// logic when Parent attribute isn't present
}
}
EDIT
If you want to get the <Array> nodes inside <AMGmers>, you can do so as below
foreach (XmlNode node in elemList1)
{
XmlNodeList arrayNodes = node.SelectNodes("Array");
foreach (XmlNode arrayNode in arrayNodes)
{
if (arrayNode.Attributes["Type"] != null)
{
// logic when Type attribute is present
// arrayNode.Attributes["Type"].Value is the value of Type attribute
}
}
}
EDIT 2
If you want to enumerate all nodes inside <AMGmers>, you can do so as below
foreach (XmlNode node in elemList1)
{
foreach (XmlNode childNode in node.ChildNodes)
{
// do whatever you want with childNode
}
}

How to get the value for multiple subnode in xml?

Xml code:
<Report>
<ChartData>
<ListName>area</ListName>
<ViewName>Selecte List</ViewName>
<YAxisFields>
<YAxisField>
<Name>Scheduled Start Date/Time</Name>
<DataType>DateTime</DataType>
<Category>Year</Category>
</YAxisField>
</YAxisFields>
<XAxisFields>
<XAxisField>
<Name>Release Type</Name>
<DataType>String</DataType>
<Category>
</Category>
</XAxisField>
</XAxisFields>
</ChartConfig>
</Report>
I got the value for the subnode listname and viewname by using the
below code,
XmlDocument doc = new XmlDocument();
doc.Load("XmlFileName");
XmlNodeList node = doc.SelectNodes("Report/ChartData");
foreach (XmlNode xn in node)
{ xn["ListName"].InnerXml = chartname;
xn["ViewName"].InnerXml = SelectedList;
**xn["YAxisFields/YAxisField"].InnerXml = yaxisfield; //not working, need to get the value for this xml node,need help in this line dono how to proceed**
doc.Save("XmlFilename");
}
First i have tried with code like this instead of above code,in this
i need to create number of objects in order get the value for each
node so i tried by creating object for xmlnodelist then i used
foreach loop to get the value for each node but in this couldnt get
the value for YAxisFields/YAxisField because it also has parent node
as YAxisFields and subnode as YAxisField so there is only way to
create number of objects for xmlnode or is there any other way to do
this?
XmlDocument doc = new XmlDocument();
doc.Load("XmlFileName");
XmlNode Listnode = doc.SelectSingleNode("Report/ChartData/ListName");
XmlNode Viewnode = doc.SelectSingleNode("Report/ChartData/ViewName");
if (Listnode != null)
{
Listnode.InnerXml = chartname;
Viewnode.InnerXml = SelectedList; ;
doc.Save("XmlFileName");
Use Linq to XML XDocument, like this:
doc.Root.Descendants("ChartData").ToList().ForEach(node =>
{
node.Element("ListName").Value = chartname;
node.Element("ViewName").Value = SelectedList;
});

Update or inserting a node in an XML doc

I am a beginner to XML and XPath in C#. Here is an example of my XML doc:
<root>
<folder1>
...
<folderN>
...
<nodeMustExist>...
<nodeToBeUpdated>some value</nodeToBeUpdated>
....
</root>
What I need is to update the value of nodeToBeUdpated if the node exists or add this node after the nodeMustExist if nodeToBeUpdated is not there. The prototype of the function is something like this:
void UpdateNode(
xmlDocument xml,
string nodeMustExist,
string nodeToBeUpdte,
string newVal
)
{
/*
search for XMLNode with name = nodeToBeUpdate in xml
to XmlNodeToBeUpdated (XmlNode type?)
if (xmlNodeToBeUpdated != null)
{
xmlNodeToBeUpdated.value(?) = newVal;
}
else
{
search for nodeMustExist in xml to xmlNodeMustExist obj
if ( xmlNodeMustExist != null )
{
add xmlNodeToBeUpdated as next node
xmlNodeToBeUpdte.value = newVal;
}
}
*/
}
Maybe there are other better and simplified way to do this. Any advice?
By the way, if nodeToBeUpdated appears more than once in other places, I just want to update the first one.
This is to update all nodes in folder:
public void UpdateNodes(XmlDocument doc, string newVal)
{
XmlNodeList folderNodes = doc.SelectNodes("folder");
if (folderNodes.Count > 0)
foreach (XmlNode folderNode in folderNodes)
{
XmlNode updateNode = folderNode.SelectSingleNode("nodeToBeUpdated");
XmlNode mustExistNode = folderNode.SelectSingleNode("nodeMustExist"); ;
if (updateNode != null)
{
updateNode.InnerText = newVal;
}
else if (mustExistNode != null)
{
XmlNode node = folderNode.OwnerDocument.CreateNode(XmlNodeType.Element, "nodeToBeUpdated", null);
node.InnerText = newVal;
folderNode.AppendChild(node);
}
}
}
If you want to update a particular node, you cannot pass string nodeToBeUpdte, but you will have to pass the XmlNode of the XmlDocument.
I have omitted the passing of node names in the function since nodes names are unlikely to change and can be hardcoded. However, you can pass these to the functions and use the strings instead of hardcoded node names.
The XPath expression that selects all instances of <nodeToBeUpdated> would be this:
/root/folder[nodeMustExist]/nodeToBeUpdated
or, in a more generic form:
/root/folder[*[name() = 'nodeMustExist']]/*[name() = 'nodeToBeUpdated']
suitable for:
void UpdateNode(xmlDocument xml,
string nodeMustExist,
string nodeToBeUpdte,
string newVal)
{
string xPath = "/root/folder[*[name() = '{0}']]/*[name() = '{1}']";
xPath = String.Format(xPath, nodeMustExist, nodeToBeUpdte);
foreach (XmlNode n in xml.SelectNodes(xPath))
{
n.Value = newVal;
}
}
Have a look at the SelectSingleNode method MSDN Doc
your xpath wants to be something like "//YourNodeNameHere" ;
once you have found that node you can then traverse back up the tree to get to the 'nodeMustExist' node:
XmlNode nodeMustExistNode = yourNode.Parent["nodeMustExist];

Categories

Resources