How to get attributes values from nested xml node? - c#

I have XElement object formated like this :
<Setting guid="3bcedf55-b75f-456b-b90a-a92cbbb022ga">
<PatientFieldList>
<PatientFieldSetting PatientName="UserDecision" PatentFieldLength="64" />
<PatientFieldSetting PatientName="prohibited" PatentFieldLength="128" />
</PatientFieldList>
</Setting>
I have to get values of all attributes in all nodes but I don't know how :/ I tried
xml.Elements("PatientFieldList")
xml.Descendants("PatientsSettingsFieldsList").Where(x => x.Attribute("PatentFieldLength").Value == 64)`
I have a lot of node like that so i wonder if there is easy way to access to these attribute by '[]' or somehow.

Code:
using System;
using System.Linq;
using System.Xml.Linq
var xml = "<Setting ...";
var doc = XElement.Parse(xml);
int i; // for int parse
var q = from node in doc.Descendants("PatientFieldSetting")
let name = node.Attribute("PatientName")
let length = node.Attribute("PatentFieldLength")
select new { Name = (name != null) ? name.Value : "", Length = (length != null && Int32.TryParse(length.Value, out i)) ? i : 0 };
foreach (var node in q)
{
Console.WriteLine("Name={0}, Length={1}", node.Name, node.Length);
}
Output:
Name=UserDecision, Length=64
Name=prohibited, Length=128

This will print out attributes of all nodes which have attributes in your xml:
XDocument doc = //your data
var q = from node in doc.Descendants()
where node.Attributes().Count() > 0
select new {NodeName = node.Name, Attributes = node.Attributes()};
foreach (var node in q)
{
Console.WriteLine( node.NodeName );
foreach (var attribute in node.Attributes)
{
Console.WriteLine(attribute.Name + ":" + attribute.Value);
}
Console.WriteLine();
}
If you only want PatientFieldSetting nodes filter for the name:
from node in doc.Descendants("PatientFieldSetting")

Related

How to get separate values from Xlement

This is a portion of XML I'm trying to parse
<BRTHDATES>
<BRTHDATE value="5/1/1963" code="B"/>
</BRTHDATES>
var birthdates = xmlDoc.XPathSelectElements("/INDV/PERSON/BRTHDATES").Elements().Where(e => e.Name == "BRTHDATE");
xe = birthdates.Elements().Where(e => e.Name == "BRTHDATE");
bbs = from b in birthdates
select new
{
Birthdays = b.FirstAttribute.Value,
Code = b?.Value
};
var status = birthdates.Elements().Where(e => e.Name.LocalName == "BRTHDATE").Single().Value;
When I try to get "Value" from the Element I get an empty string. I can't get anything for the "code" attribute.
It sure seems like this should be a lot easier...
You can try below code. I've already tested through a test project and got the require value.
string personBirthday = string.Empty;
string soapResult = #"<?xml version=""1.0"" encoding=""utf - 8"" ?><INDV> <PERSON> <BRTHDATES><BRTHDATE value = ""5/1/1963"" code = ""B"" /> </BRTHDATES></PERSON></INDV> ";
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(soapResult));
XmlNodeList person = doc.GetElementsByTagName("BRTHDATES");
if (person[0].ChildNodes.Count > 0)
{
foreach (XmlNode item in person[0].ChildNodes)
{
if (item.Name.Trim().Equals("BRTHDATE"))
{
personBirthday = !string.IsNullOrEmpty(item.Attributes[0].Value) ? item.Attributes[0].Value.Trim() : string.Empty;
}
}
}
Here is the solution
You can select specific Element from a Xml. Just try below sample code
XmlNodeList generalTabNodeList = xmlDocument.SelectNodes("/INDV/PERSON/BRTHDATES");
foreach (XmlNode node in generalTabNodeList)
{
if (node.ChildNodes.Count > 0)
{
string birthdate = !string.IsNullOrEmpty(node.ChildNodes[0].ToString()) ? node.ChildNodes[2].InnerText.ToString() : string.Empty;
}
}
I can't quite follow what you are trying to do, but, this should get you going:
For an XML file that looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<INDV>
<PERSON>
<BRTHDATES>
<BRTHDATE value="5/1/1963" code="B"/>
</BRTHDATES>
</PERSON>
</INDV>
(Note, this is an entire XML document - one that matches your code, not just the snippet you provided (that doesn't match your code))
This code will pick out the value and code attributes:
using (var xmlStream = new FileStream("Test.xml", FileMode.Open))
{
XDocument xmlDocument = XDocument.Load(xmlStream);
var birthDateElements = xmlDocument.XPathSelectElements("/INDV/PERSON/BRTHDATES/BRTHDATE");
var birthDateElement = birthDateElements.FirstOrDefault();
if (birthDateElement != null)
{
var attributes = birthDateElement.Attributes();
var valueAttribute = attributes.Where(a => a.Name == "value");
var codeAttribute = attributes.Where(a => a.Name == "code");
}
}
You can play around with this code to figure out what you want to do. Whatever you do, don't pick out attributes by position, pick them out by name.

Get all the attribute values by attribute name from XML file using Linq to XML

I have an XML file and I have to extract all the attribute values from XML. I have tried the below one but I need it in Linq. Can anyone guide me how to do this.
Sample XML
<MapFile>
<Import>
<field name1="BorrowId" name2="EMPLID" />
<field name1="Firstname" name2="COMPLETENAME" />
<field name1="Address" name2="Address" Reference="Location" />
</Import>
<Location>
<Lookup Key="CC" Replace="1" />
<Lookup Key="CE" Replace="2" />
</Location>
</MapFile>
Expected Result
[0]:
CurrentVal = "BorrowId"
NewVal = "EMPLID"
Reference = null
ReferenceList = null
[1]:
CurrentVal = "Firstname"
NewVal = "COMPLETENAME"
Reference = null
ReferenceList = null
[2]:
CurrentVal = "Address"
NewVal = "Address"
Reference = "Location"
ReferenceList = [0]:
Key = "CC"
Value = "1"
[1]:
Key = "CE"
Value = "2"
Code
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#sPath);
var attrValues = xmlDoc.GetElementsByTagName("field");
List<MapFileModel> MapFileMod = new List<MapFileModel>();
foreach (XmlNode x in attrValues)
{
MapFileModel _objMapFile = new MapFileModel();
if (x.Attributes["name1"] != null)
{
_objMapFile.CurrentVal = x.Attributes["name1"] != null ? x.Attributes["name2"].Value : null;
_objMapFile.NewVal = x.Attributes["name2"] != null ? x.Attributes["name2"].Value : null;
_objMapFile.Reference = x.Attributes["Reference"] != null ? x.Attributes["Reference"].Value : null;
}
MapFileMod.Add(_objMapFile);
}
Okay, so it looks like you want something like this, which loads all the field elements in the Import just-below-root element, then loads the reference lists by finding every element which isn't Import.
var doc = XDocument.Load("foo.xml");
var replacements = doc
.Root
.Element("Import")
.Elements("field")
.Select(x => new Replacement {
CurrentValue = (string) x.Attribute("name1"),
NewValue = (string) x.Attribute("name2"),
Reference = (string) x.Attribute("reference")
})
.ToList();
var referenceLists = doc
.Root
.Elements()
.Where(f => f.Name.LocalName != "Import")
.ToDictionary(
x => x.Name.LocalName,
x => x.Elements("Lookup")
.Select(l => new KeyValuePair<string, string>(
(string) l.Attribute("Key"),
(string) l.Attribute("Replace"))
.ToList()
);
You'd then look up the Replacement.Reference in ReferenceLists to get the key/value pair list.
Something like this?
https://forums.asp.net/t/1964585.aspx?how+to+read+xml+elements+using+linq+in+c+net+recursively+
Must be improved but :
string strFilename = "/Message.xml";
strFilename = Server.MapPath(strFilename);
XmlDocument xmlDoc = new XmlDocument();
if (File.Exists(strFilename))
{
XmlTextReader rdrXml = new XmlTextReader(strFilename);
do
{
switch (rdrXml.NodeType)
{
case XmlNodeType.Text:
//Console.WriteLine("{0}", rdrXml.Value);
Response.Write(rdrXml.Value + "<br/>");
break;
}
} while (rdrXml.Read());
}
See below is a generic program that parses the xml string and recursively prints attribute name and value. I hope you can check if the name is a reference value per your requirement and go from over there..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
string xmlstring = #"<MapFile>
<Import>
<field name1=""BorrowId"" name2=""EMPLID"" />
<field name1=""Firstname"" name2=""COMPLETENAME"" />
<field name1=""Address"" name2=""Address"" Reference=""Location"" />
</Import>
<Location>
<Lookup Key=""CC"" Replace=""1"" />
<Lookup Key=""CE"" Replace=""2"" />
</Location>
</MapFile>";
XElement xmlTree = XElement.Parse(xmlstring);
ParseChildElement(xmlTree);
Console.ReadLine();
}
static void ParseChildElement(XElement xmlTree)
{
PrintAttributes(xmlTree);
foreach(XElement element in xmlTree.Elements())
{
ParseChildElement(element);
}
}
static void PrintAttributes(XElement xmlTree)
{
foreach (XAttribute attr in xmlTree.Attributes())
{
string[] attribArray = attr.ToString().Split('=');
if (attribArray.Length > 1)
Console.WriteLine(string.Format(#" {0} = {1}", attr.Name, attr.Value));
}
}
}
}

Not able to read XML string in C#

I have created a XML string and Looping that to get value. But its not entering in foreach loop. But in my other code same loop code is working.
my code is :
XML string:
<SuggestedReadings>
<Suggestion Text="Customer Centricity" Link="http://wdp.wharton.upenn.edu/book/customer-centricity/?utm_source=Coursera&utm_medium=Web&utm_campaign=custcent" SuggBy="Pete Fader�s" />
<Suggestion Text="Global Brand Power" Link="http://wdp.wharton.upenn.edu/books/global-brand-power/?utm_source=Coursera&utm_medium=Web&utm_campaign=glbrpower" SuggBy="Barbara Kahn�s" />
</SuggestedReadings>
Code Is:
string str = CD.SRList.Replace("&", "&");
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(str);
XmlNode SuggestionListNode = xmlDoc.SelectSingleNode("/SuggestedReadings/Suggestion");
foreach (XmlNode node in SuggestionListNode)
{
COURSESUGGESTEDREADING CSR = new COURSESUGGESTEDREADING();
var s = db.COURSESUGGESTEDREADINGS.OrderByDescending(o => o.SRID);
CSR.SRID = (s == null ? 0 : s.FirstOrDefault().SRID) + 1;
CSR.COURSEID = LibId;
CSR.TEXT = node.Attributes.GetNamedItem("Text").Value;
CSR.LINK = node.Attributes.GetNamedItem("Link").Value; ;
CSR.SUGBY = node.Attributes.GetNamedItem("SuggBy").Value; ;
CSR.ACTIVEFLAG = "Y";
CSR.CREATEDBY = CD.CreatedBy;
CSR.CREATEDDATE = DateTime.Now;
db.COURSESUGGESTEDREADINGS.Add(CSR);
}
You should use SelectNodes, not SelectSingleNode, since you are trying to get multiple rows out of the XML document.
Use this:
XmlNodeList SuggestionListNode = xmlDoc.SelectNodes("//Suggestion");
foreach (XmlNode node in SuggestionListNode)
{
}
You can try this.
XDocument xdoc = XDocument.Load("data.xml");
var xmlData = from lv1 in xdoc.Descendants("Suggestion")
select new {
Text = lv1.Attribute("Text").Value,
Link = lv1.Attribute("Link").Value,
SuggBy = lv1.Attribute("SuggBy").Value
};
foreach (var item in xmlData){
// your logic here
}

Count child nodes of node matching listbox item

Im having a problem here with selected index change. My xml file contains module number, module name, assesments, credits etc. What im trying to achieve here is - some course details are loaded into listbox from xml (module name and code) but when user selects a module, label should display how many assessments that module has.
Here is my XML file sample
<module>
<moduleCode>ECWM618</moduleCode>
<moduleTitle>Semantic and Social Web</moduleTitle>
<credits>15</credits>
<semester>2</semester>
<assessmentDetails>
<assessment>
<assessmentName>Coursework1</assessmentName>
<assessmentType>Coursework</assessmentType>
<assessmentWeighting>25</assessmentWeighting>
</assessment>
<assessment>
<assessmentName>Coursework2</assessmentName>
<assessmentType>Coursework</assessmentType>
<assessmentWeighting>25</assessmentWeighting>
</assessment>
<assessment>
<assessmentName>Exam</assessmentName>
<assessmentType>Exam</assessmentType>
<assessmentWeighting>50</assessmentWeighting>
</assessment>
</assessmentDetails>
</module>
And here is the code i got
private void moduleSummaryBox_SelectedIndexChanged(object sender, EventArgs e)
{
// when module from modulelist is selected, it read all indicies assigned to the module.
//!!!!!!!! it reads last node only :(? wtf im tired ...lol
//
// read data from modulelist
string path = Directory.GetCurrentDirectory();
FileStream fs = new FileStream(#"myCourse.xml", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
XmlReader moduleReader = XmlReader.Create(fs);
moduleReader.Read();
while (moduleReader.Read())
{
int assessmentNo = 0;
bool match = false;
moduleReader.MoveToElement();
if (moduleReader.Name == "assessmentName")
{
moduleReader.Read();// reads xml file.
XmlNodeType nType = moduleReader.NodeType; //XmlNodeType Specifies the type of node. If node matches specified name = true.
if (nType == XmlNodeType.Text)// if node type match XmlNodeType ( and there is some text in it) statement becomes true
{
this.assno.Text = (moduleReader.Value.ToString()); //set mcode label to matched node.
}
}
if (moduleReader.Value.ToString() == moduleSummaryBox.Items[moduleSummaryBox.SelectedIndex].ToString())
{
match = true;
}
if (match == true)
{
break;
}
}
}
Help appreciated thank you :)
EDIT:
This is what goes into listbox
moduleSummaryBox.Items.Clear();
XmlDocument doc = new XmlDocument();
doc.Load(#"myCourse.xml");
XmlNodeList levelList = doc.GetElementsByTagName("level"+l_level);
foreach (XmlNode node in levelList)
{
XmlElement moduleElement = (XmlElement)node;
XmlNodeList modules_individ = moduleElement.GetElementsByTagName("module");
foreach (XmlNode nodes in modules_individ)
{
XmlElement moduleSeperator = (XmlElement)nodes;
string ll_moduleCode = moduleSeperator.GetElementsByTagName("moduleCode")[0].InnerText;
string ll_moduleTitle = moduleSeperator.GetElementsByTagName("moduleTitle")[0].InnerText;
moduleSummaryBox.Items.Add(ll_moduleCode+" : " + ll_moduleTitle+" ");
}
}
Can you Try With the code sample below:-
const string xmlString =
"<module><moduleCode>ECWM618</moduleCode><moduleTitle>Semantic and Social Web</moduleTitle><credits>15</credits>" +
"<semester>2</semester><assessmentDetails><assessment><assessmentName>Coursework1</assessmentName><assessmentType>Coursework</assessmentType>" +
"<assessmentWeighting>25</assessmentWeighting></assessment><assessment><assessmentName>Coursework2</assessmentName><assessmentType>Coursework</assessmentType>" +
"<assessmentWeighting>25</assessmentWeighting></assessment><assessment><assessmentName>Exam</assessmentName><assessmentType>Exam</assessmentType><assessmentWeighting>50</assessmentWeighting></assessment></assessmentDetails></module>";
var xml = XElement.Parse(xmlString);
var qry =
xml.Descendants()
.Where(e => e.Name == "moduleCode" && e.Value == "ECWM618")
.Ancestors()
.Descendants()
.Where(e => e.Name == "assessmentDetails")
.Elements("assessment").Count();

C# : Getting all nodes of XML doc

Is there a simple way, to get all nodes from an xml document? I need every single node, childnode and so on, to check if they have certain attributes.
Or will I have to crawl through the document, asking for childnodes?
In LINQ to XML it's extremely easy:
XDocument doc = XDocument.Load("test.xml"); // Or whatever
var allElements = doc.Descendants();
So to find all elements with a particular attribute, for example:
var matchingElements = doc.Descendants()
.Where(x => x.Attribute("foo") != null);
That's assuming you wanted all elements. If you want all nodes (including text nodes etc, but not including attributes as separate nodes) you'd use DescendantNodes() instead.
EDIT: Namespaces in LINQ to XML are nice. You'd use:
var matchingElements = doc.Descendants()
.Where(x => x.Attribute(XNamespace.Xmlns + "aml") != null);
or for a different namespace:
XNamespace ns = "http://some.namespace.uri";
var matchingElements = doc.Descendants()
                    .Where(x => x.Attribute(ns + "foo") != null);
see here: Iterating through all nodes in XML file
shortly:
string xml = #"
<parent>
<child>
<nested />
</child>
<child>
<other>
</other>
</child>
</parent>
";
XmlReader rdr = XmlReader.Create(new System.IO.StringReader(xml));
while (rdr.Read())
{
if (rdr.NodeType == XmlNodeType.Element)
{
Console.WriteLine(rdr.LocalName);
}
}
In my opinion the simplest solution is using XPath. Also this works if you have .NET 2:
var testDoc = new XmlDocument();
testDoc.LoadXml(str);
var tmp = testDoc.SelectNodes("//*"); // match every element
XDocument.Descendants will return you all the nodes in a flat enumerable.
Check out LINQ to XML. That does what you need.
http://www.hookedonlinq.com/LINQtoXML5MinuteOverview.ashx
You can use the SelectMany extension for example.
But if you want to check the values you can just use LINQ to create where-statements.
public void AddWithChildren(XmlNode xnod, Int32 intLevel) //,XmlDocument xmlDoc
{
List<IEnumerable> item = new List<IEnumerable>();
XmlNode xnodWorking;
String strIndent = new string('-', 2 * intLevel);
String strIndent1 = new string('#', 2 * intLevel);
if (xnod.NodeType == XmlNodeType.Element)
{
item.Add(new ListXML(strIndent + xnod.Name, strIndent + xnod.Name, ""));
XmlNamedNodeMap mapAttributes = xnod.Attributes;
foreach (XmlNode xnodAttribute in mapAttributes)
{
item.Add(new ListXML(strIndent1 + xnodAttribute.Name, strIndent1 + xnodAttribute.Name, ""));
}
if (xnod.HasChildNodes)
{
xnodWorking = xnod.FirstChild;
while (xnodWorking != null)
{
AddWithChildren(xnodWorking, intLevel + 1);
xnodWorking = xnodWorking.NextSibling;
}
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
XmlDocument document = new XmlDocument();
string xmlStr;
using (var wc = new WebClient())
{
xmlStr = wc.DownloadString("test.xml");
}
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlStr);
XmlNode xnod = xmlDoc.DocumentElement;
AddWithChildren(xnod, 1);
}
string AttrNameerr = "err";//find error code in xml
XmlReader rdr = XmlReader.Create(new stem.IO.StringReader(somesXMLtring));//somesXMLtring is xml in string variable we want to find attribute in.
while (rdr.Read())
{
if (rdr.NodeType == XmlNodeType.Element)
{
//Found the new element, now check if the required attribute is present or not. if not, ignore, if yes then display the same
string val = rdr.GetAttribute(AttrNameerr);//AttrNameerr is name of attribute we need to get value of which. here we are searching for error code stored as value of 'err' attribute
if (val != null)
textBox.Text = strResult = "error = " + rdr.GetAttribute(AttrNameerr);
}
}

Categories

Resources