Find node recursively in xml document - c#

<TestSuite name="TestSuite1">
<TestCase name="TestCase1" UID="1" State="1" DataSourceId="1">
<TestModule name="Recording1" State="Checked" UID="1">
</TestModule>
<TestCase name="TestCase3" UID="bde575e2-74dd-4b5b-9d92-c12cc7e6777d" State="Checked" DataSourceId="" />
</TestCase>
<TestCase name="TestCase2" UID="06a4df3b-f072-4f70-a5c3-f0f2ea95654c" State="Checked" DataSourceId="" />
<TestModule name="ds" State="Checked" UID="16b175a7-b286-484d-ba9a-2a5c9f8dd0fc" />
<TestModule name="hh" State="Checked" UID="581f5d85-a777-483b-9b5d-ae2830302878" />
</TestSuite>
XmlNode rootNode = xDoc.SelectSingleNode("/TestSuite");
string s = "16b175a7-b286-484d-ba9a-2a5c9f8dd0fc";
XmlNode l_objXmlNode = null;
foreach (XmlNode node in rootNode.ChildNodes)
{
l_objXmlNode = ProcesNode(node, s);
if (l_objXmlNode != null)
break;
}
private static XmlNode ProcesNode(XmlNode node, string l_selectedNodeUID)
{
XmlNode l_objXmlNode = null;
if (!node.HasChildNodes
|| ((node.ChildNodes.Count == 1) && (node.FirstChild is System.Xml.XmlText)))
{
if (node.Attributes["UID"] != null && node.Attributes["UID"].Value == l_selectedNodeUID)
{
l_objXmlNode = node;
return l_objXmlNode;
}
}
else
{
foreach (XmlNode child in node.ChildNodes)
{
if (child.Attributes["UID"] != null && child.Attributes["UID"].Value == l_selectedNodeUID)
{
l_objXmlNode = child;
break;
}
else
{
return ProcesNode(child, l_selectedNodeUID);
}
}
}
return l_objXmlNode;
}'
I have to find deepest child node from xml file having UID="value" for that i have written above recursive code but l_objXmlNode always giving me null value.I have to find deepest child node from xml file having UID="value" for that i have written above recursive code but l_objXmlNode always giving me null value.

You can use XPath expression to find element with UID attribute equals certain value, anywhere in the XML document :
....
string s = "16b175a7-b286-484d-ba9a-2a5c9f8dd0fc";
XmlNode l_objXmlNode = xDoc.SelectSingleNode(String.Format("//*[#UID='{0}']", s));
Or using LINQ-to-XML :
XDocument doc = XDocument.Load("path to your XML file");
string s = "16b175a7-b286-484d-ba9a-2a5c9f8dd0fc";
XElement l_objXmlNode = doc.Descendants().FirstOrDefault(o => (string)o.Attribute("UID") == s);

Try this...
public static void SearchNodes()
{
XDocument doc = XDocument.Load(#"D:\\Test\\Test2.xml");
var v = from nodes in doc.Descendants("TestCase")
where nodes.Attribute("UID").Value == "06a4df3b-f072-4f70-a5c3-f0f2ea95654c"
select nodes;
foreach (var item in v)
{
Console.Write(item);
}
}
You will get following output
<TestCase name="TestCase2" UID="06a4df3b-f072-4f70-a5c3-f0f2ea95654c" State="Che
cked" DataSourceId="" />
You can pass the expected value as parameter to SearchNodes function.

Related

How to get attributes from XML in C#

I am getting output xml format in that can able to access appointment-nbr, but I am not able to eqid. How can I get slot-start,slot-end,eqid.
> <appointment-nbr>494</appointment-nbr> <slot
> slot-start="2018-07-16T12:31:00" slot-end="2018-07-16T13:00:00" />
> <appointment requires-xray="false" /> <container eqid="ASWU2705080" />
This is my code:
foreach (XmlNode node in appointmentsresponce){
XmlElement flightEle = (XmlElement)node;
XmlNodeList appointmentnbr = flightEle.GetElementsByTagName("appointment-nbr");
XmlNodeList containerNodeList = flightEle.GetElementsByTagName("container");
}
Try (I'm guessing a bit since you didn't post the full data):
foreach (XElement level1Element in XElement.Load(#"your_file.xml").Elements("appointment-nbr"))
{
foreach (XElement level2Element in level1Element.Elements("slot"))
{
Console.WriteLine(level1Element.Attribute("slot-start").Value);
}
}
Simple call GetAttribute("AttributeName") on your XmlElement
So:
var slotXml = appointmentsresponce.SelectSingleNode("//slot")
var startAttr = slotXml.GetAttribute("slot-start")
var endAttr = slotXml.GetAttribute("slot-end")
var containerXml = appointmentsresponce.SelectSingleNode("//container ")
var eqidAttr = containerXml .GetAttribute("eqid")

Linq to XML Find a an attribute and return seperate attribute value

<?xml version="1.0" ?>
<aliasSection>
<aliases>
<clear />
<add
name="MAIN"
server="JAG8MTO\SQLEXPRESS"
database="RMain"
trustedConnection="false" />
<add
name="DEMO"
server="JAG8MTO\SQLEXPRESS"
database="RDemo"
trustedConnection="false" />
</aliases>
</aliasSection>
In the above xml doc I need to search for an alias name then return the server and database attributes.
This is my first time working with xml docs and I'm having a hard time wrapping my head around it.
So far I have this, I can find the aliases section but I'm at a loss have to proceed from here.
public void Read(string fileName)
{
XDocument doc = XDocument.Load(fileName);
foreach (XElement el in doc.Root.Elements())
{
foreach (XAttribute attr in el.Attributes())
if (attr.ToString() == "aliases")
{
foreach (XElement element in el.Elements())
listBox1.Items.Add(element.Name + " " + element.Value);
foreach (XAttribute attrib in el.Attributes())
listBox1.Items.Add(attrib.Value);
}
}
}
aliases is element, not attribute
var document = XDocument.Load(fileName);
var data =
document.Descendants("aliases") // Select all <aliases> elements
.SelectMany(alias => alias.Elements("add")) // select all <add> elements
.Select(add => new
{
Name = add.Attribute("name").Value
Server = add.Attribute("server").Value
})
.ToList();
listBox1.Items.AddRange(data);
data will contain selected values of all <add> elements.
foreach (var item in data)
{
Console.WriteLine($"Name: {item.Name}, Server: {item.Server}");
}
// Load the xml into XElement
XDocument doc = XDocument.Load("F:\\db.xml",LoadOptions.None);
// Search through descendants and
// find one with name as MAIN
XElement result = doc.Descendants("add")
.FirstOrDefault(y => y.Attribute("name") != null &&
y.Attribute("name").Value == "MAIN");
// Get the values if valid element is found
if(result != null)
{
string server = (result.Attribute("server") != null) ? result.Attribute("server").Value : string.Empty;
string database = (result.Attribute("database") != null) ? result.Attribute("database").Value : string.Empty;
}

How do I get number of a XML nodes child in c# XmlReader?

this is my XML structure:
<classes>
<Base Name="node1">
<Book Name="child01" CoverArtName="C102.jpg" CoverBaseFolder="" Tooltip="" PluginBook=""/>
<Book Name="child02" CoverArtName="C102.jpg" CoverBaseFolder="" Tooltip="" PluginBook=""/>
<Book Name="child03" CoverArtName="C102.jpg" CoverBaseFolder="" Tooltip="" PluginBook=""/>
</Base >
<Base Name="node2">
<Book Name="child01" CoverArtName="C102.jpg" CoverBaseFolder="" Tooltip="" PluginBook=""/>
<Book Name="child02" CoverArtName="C102.jpg" CoverBaseFolder="" Tooltip="" PluginBook=""/>
</Base >
<Base Name="node3">
</Base >
</classes>
how can i get number of children of each node with xmlReader?
Update:
I read my XML with thes code:
List<Bases> base7 = new List<Bases>();
XmlReader xmlReader = XmlReader.Create("Books.xml");
while (xmlReader.Read())
{
if ((xmlReader.NodeType == XmlNodeType.Element) && (xmlReader.Name == "Base"))
{
if (xmlReader.HasAttributes)
Console.WriteLine(xmlReader.GetAttribute("Name") + ": " + xmlReader.GetAttribute("CoverBaseFolder"));
//Base Name
base7.Add(new Bases() { BaseName = xmlReader.GetAttribute("Name"), Basefolder = xmlReader.GetAttribute("CoverBaseFolder") });
}
}
mainbox.ItemsSource = base7;
The output is a list item with name of node and number of child elements of same node.
This can be done easily by using LinqToXml:
var list = XElement.Load("test.xml")
.Elements("Base")
.Select(e => new
{
Name = e.Attribute("Name").Value,
Count = e.Elements().Count()
})
.ToList();
But if you want to use the XmlReader, for example, to work with xml that does not fit in memory, the code is much more cumbersome:
var bases = new List<Base>();
using (var xmlReader = XmlReader.Create("test.xml"))
{
while (xmlReader.Read())
{
if ((xmlReader.NodeType == XmlNodeType.Element) && (xmlReader.Name == "Base"))
{
var name = xmlReader.GetAttribute("Name");
int count = 0;
using (var innerReader = xmlReader.ReadSubtree())
{
while (innerReader.Read())
{
if (innerReader.NodeType == XmlNodeType.Element && innerReader.Name == "Book")
count++;
}
}
bases.Add(new Base { Name = name, Count = count });
}
}
}
class Base
{
public string Name { get; set; }
public int Count { get; set; }
}
To count the child nodes is convenient to use the ReadSubtree method.
The XmlReader class has many useful methods. Use ReadToFollowing method allows to slightly reduce code.
var bases = new List<Base>();
using (var xmlReader = XmlReader.Create("test.xml"))
{
while (xmlReader.ReadToFollowing("Base"))
{
string name = xmlReader.GetAttribute("Name");
int count = 0;
using (var innerReader = xmlReader.ReadSubtree())
{
while (innerReader.ReadToFollowing("Book"))
count++;
}
bases.Add(new Base { Name = name, Count = count });
}
}

read xml document and update all fields c#

i'm trying to read xml file and update all it's value my xml was
<adf>
<prospect>
<requestdate>2015-10-29 07-38-22</requestdate>
<id sequence="1" source="admin.ss.com">admin.ss.com</id>
<vehicle interest="buy" status="">
<id sequence="1" source=""></id>
<year></year>
<make></make>
<model>camry</model>
<vin></vin>
<stock></stock>
<trim></trim>
</vehicle>
<customer>
<contact primarycontact="1">
<name part="first">Jessica</name>
<name part="last">Sonntag</name>
<email>js#test.com</email>
<phone type="phone" time="day">555-585-5555</phone>
<address>
<street line="1"></street>
<city></city>
<regioncode></regioncode>
<postalcode></postalcode>
<country></country>
</address>
</contact>
<comments>Vehicle Year: 2011 Comments: </comments>
</customer>
<provider>
<name part="full">ST</name>
<service> Engine Marketing</service>
<phone>1-866-572-3952</phone>
</provider>
</prospect>
</adf>
so i select node like below
var items = (from item in xmlDoc.Descendants("requestdate")
select item).ToList();
then i can update only requestdata tag value so do i have to repeat same for all tags or is there any good way to accomplish this.
Regards
There is an easy way to do this. This one is a hidden gem. Most people may not know this. This feature came in VS2013 and it's called "Paste XML as Classes."
Save your xml (Ex: MyXml.XML)
Create a new Console project
Open the Xml in Visual studio
Copy All contents of the xml (Ctl+A, Ctl + C)
Add a new class to your project. You can give any name you like.
Go to Edit>Paste Special>Paste XML as classes.
Add another class to your project. Then add below two methods to that class.
public static string Serialise<T>(T serialisableObject)
{
var doc = new XmlDocument();
using (var stream = new StringWriter())
{
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlWriter xmlWriter = XmlWriter.Create(stream, settings);
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(xmlWriter, serialisableObject, ns);
doc.LoadXml(stream.ToString());
}
return doc.InnerXml;
}
public static T Deserialise<T>(string xml)
{
T list;
using (var reader = new StringReader(xml))
{
var serialiser = new XmlSerializer(typeof(T));
list = (T)serialiser.Deserialize(reader);
}
return list;
}
Then in your console applications Main method; add this.
var myObj = new adf();
myObj.prospect = new adfProspect();
myObj.prospect.customer = new adfProspectCustomer(){comments = "dgsrtetetete"};
//populate all fields.....
var xml = MySerializer.Serialise(myObj);
File.WriteAllText(#"C:\myNewXml.xml", xml);
That's it. Same way now you can deserialise an xml object in to your class.
Try the XmlSerializer class: https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer(v=vs.110).aspx If you serialize/deserialize the xml then up dating is trivial.
If you wanted to change every phone number to "0123456789" you could do something like:
var xDoc = XDocument.Load("document.xml");
var results = from phone in xDoc.Descendants("phone") select phone;
foreach (XElement result in results)
{
element.SetValue("0123456789");
}
i have came up with solution with support two extension method i'm iterating all nodes and update.(since my xml is not too big or complicated this one would be a good solution)
with help of these two extension methods
public static void IterateThroughAllNodes(this XmlDocument doc, Action<XmlNode> elementVisitor)
{
if (doc != null && elementVisitor != null)
{
foreach (XmlNode node in doc.ChildNodes)
{
DoIterateNode(node, elementVisitor);
}
}
}
public static void IterateThrough(this XmlNodeList nodes, Action<XmlNode> elementVisitor)
{
if (nodes != null && elementVisitor != null)
{
foreach (XmlNode node in nodes)
{
DoIterateNode(node, elementVisitor);
}
}
}
private static void DoIterateNode(XmlNode node, Action<XmlNode> elementVisitor)
{
elementVisitor(node);
foreach (XmlNode childNode in node.ChildNodes)
{
DoIterateNode(childNode, elementVisitor);
}
}
then i can update my xml nodes as below
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("~/xmlmail.xml"));
var email = new XmlEmail();
doc.IterateThroughAllNodes(
delegate(XmlNode node)
{
if (node.Name.Equals("requestdate"))
node.InnerText= email.RequestDate.ToLongDateString();
if (node.Name.Equals("vehicle"))
{
XmlNodeList childs = node.ChildNodes;
childs.IterateThrough(delegate(XmlNode vnode)
{
if (vnode.Name.Equals("id"))
vnode.InnerText= email.VehicleId.ToString();
if (vnode.Name.Equals("year"))
vnode.InnerText= email.Year.ToString();
if (vnode.Name.Equals("make"))
vnode.InnerText= email.Make;
if (vnode.Name.Equals("model"))
vnode.InnerText= email.Model;
if (vnode.Name.Equals("vin"))
vnode.InnerText= email.Vin;
if (vnode.Name.Equals("trim"))
vnode.InnerText = email.Trim;
});
}
if (node.Name.Equals("customer"))
{
XmlNodeList childs = node.ChildNodes;
childs.IterateThrough(delegate(XmlNode vnode)
{
if (vnode.Attributes != null && (vnode.Name.Equals("name") && vnode.Attributes["part"].Value.Equals("first")))
vnode.InnerText= email.FirstName;
if (vnode.Attributes != null && (vnode.Name.Equals("name") && vnode.Attributes["part"].Value.Equals("last")))
vnode.InnerText= email.LastName;
if (vnode.Name.Equals("email"))
vnode.InnerText= email.Email;
if (vnode.Name.Equals("phone"))
vnode.InnerText= email.Phone;
if (vnode.Name.Equals("comments"))
vnode.InnerText= email.Comments;
if (vnode.Name.Equals("address"))
{
XmlNodeList addresschilds = vnode.ChildNodes;
addresschilds.IterateThrough(delegate(XmlNode anode)
{
if (anode.Name.Equals("street"))
anode.InnerText= email.Street;
if (anode.Name.Equals("city"))
anode.InnerText= email.City;
if (anode.Name.Equals("phone"))
anode.InnerText= email.Phone;
if (anode.Name.Equals("regioncode"))
anode.InnerText= email.RegionCode;
if (anode.Name.Equals("postalcode"))
anode.InnerText= email.Postalode;
if (anode.Name.Equals("country"))
anode.InnerText= email.Country;
});
}
});
}
});

How to set a value in XML using C#?

How to change the value of sourcePatientInfo in the following xml file using c#.
I can able to read the value using,
var elem = (from n in xml.Descendants("Slot")
where n.Attribute("name").Value == "sourcePatientInfo"
select n).FirstOrDefault();
How to change the same using C#?
<?xml version="1.0" encoding="utf-8"?>
<rs:SubmitObjectsRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rs="urn:oasis:names:tc:ebxml-regrep:registry:xsd:2.1" xmlns:rim="urn:oasis:names:tc:ebxml-regrep:rim:xsd:2.1" xmlns="urn:oasis:names:tc:ebxml-regrep:rim:xsd:2.1">
<LeafRegistryObjectList>
<ObjectRef id="urn:uuid:93606bcf-9494-43ec-9b4e-a7748d1a838d" />
<ExtrinsicObject id="Document01" mimeType="application/dicom" objectType="urn:uuid:7edca82f-054d-47f2-a032-9b2a5b5186c1">
<Name>
<LocalizedString value="Physical" />
</Name>
<Description />
<Slot name="sourcePatientId">
<ValueList>
<Value>pid1^^^&1.2.3&ISO</Value>
</ValueList>
</Slot>
<Slot name="sourcePatientInfo">
<ValueList>
<Value>PID-3|pid1^^^&1.2.3&ISO</Value>
<Value>PID-5|Doe^John^^^</Value>
<Value>PID-7|19560527</Value>
<Value>PID-8|M</Value>
<Value>PID-11|100 Main St^^Metropolis^Il^44130^USA</Value>
</ValueList>
</Slot>
I would like to change the values using c#. Am not able to figure out the way. Any Help to resolve this issue will be appreciated.
I want to change the
<Slot name="sourcePatientInfo">
<ValueList>
<Value>PID-3|pid1^^^&1.2.3&ISO</Value>
<Value>PID-5|Doe^John^^^</Value>
to the following value
<Slot name="sourcePatientInfo">
<ValueList> <Value>PID-3|MyPID</Value>
<Value>PID-5|MyName</Value>
I have also tried the following the code,
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmlDoc1.NameTable);
namespaceManager.AddNamespace("rs", "urn:oasis:names:tc:ebxml-regrep:registry:xsd:2.1");
var query = "/rs:SubmitObjectsRequest/LeafRegistryObjectList/ExtrinsicObject";
XmlNodeList nodeList = xmlDoc1.SelectNodes(query, namespaceManager);
foreach (XmlNode node1 in nodeList)
{
if (node1.Attributes["Slot"].Value == "sourcePatientInfo")
{
node1.Attributes["ValueList"].Value = "Myvalue";
}
}
In this code, nodelist.count is always zero :-(. Kindly help me to resolve the issue.
If you need to update first two values:
var slot = xml.Descendants("Slot")
.Where(n => n.Attribute("name").Value == "sourcePatientInfo")
.FirstOrDefault();
if(slot == null)
{
throw new WhateverAppropriateHereEcxeption();
}
var values = slot.Descendants("Value").ToList();
if(values.Count < 2)
{
throw new WhateverAppropriateHereEcxeption();
}
values[0].Value = "PID-3|MyPID" // updating the first value
values[1].Value = "PID-5|MyName" // updating the second value
if you have to search by value you can do:
bool UpdateValue(XElement slot, string oldValue, string newValue)
{
var elem = slot.Descendants("Slot")
.Where(n => n.Name == "Value" && n.Value == oldValue)
.FirstOrDefault();
if(elem != null)
{
elem = newValue;
return true;
}
return false;
}
and inside some function
var slot = xml.Descendants("Slot")
.Where(n => n.Attribute("name").Value == "sourcePatientInfo")
.FirstOrDefault();
if(slot == null)
{
throw new WhateverAppropriateHereEcxeption();
}
UpdateValue(slot, "PID-3|pid1^^^&1.2.3&ISO", "PID-3|MyPID");
UpdateValue(slot, "PID-5|Doe^John^^^", "PID-5|MyName");
UPD when you call xml.Descendants("Slot") xml look only for elements in default namespace. I use an extension method as a quick workaround to avoid that:
public static IEnumerable<XElement> NsDescendants(this XContainer e, string elementName)
{
return e.Descendants().Where(d => d.Name.LocalName == elementName);
}
Finally my problem is solved with the following code.
XmlDocument xmlDocSOR = new XmlDocument();
XmlDocSOR.Load("filename.xml");
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmlDocSOR.NameTable);
namespaceManager.AddNamespace("rs", "urn:oasis:names:tc:ebxml-regrep:registry:xsd:2.1");
namespaceManager.AddNamespace("ns", "urn:oasis:names:tc:ebxml-regrep:rim:xsd:2.1");
var query = "/rs:SubmitObjectsRequest/ns:LeafRegistryObjectList/ns:ExtrinsicObject/ns:Slot";
XmlNodeList nodeList = xmlDocSOR.SelectNodes(query, namespaceManager);
foreach (XmlNode plainnode in nodeList)
{
if (plainnode.Attributes["name"].Value == "sourcePatientId")
{
XmlNode childnode = plainnode.LastChild;
XmlElement ee1 = (XmlElement)childnode.FirstChild;
ee1.InnerText = sPatientID;
}
}
xmlDocSOR.Save("filename.xml");

Categories