i have an xml document of this kind
<xml>
<person name="a">
<age>21</age>
<salary>50000></salary>
</person>
<person name="b">
<age>25</age>
<salary>30000></salary>
</person>
<person name="c">
<age>30</age>
<salary>60000></salary>
</person>
<person name="d">
<age>35</age>
<salary>150000></salary>
</person>
</xml>
Now im trying to validate this document by passing this to a method like this
validate(string file)
{
// here i have some logic
// say i am trying to check if the salary is >50000 and age > 30
// if it doesn't satisfy the condition i have to return an error
}
I am able to achieve this . What i really want is to know where exactly the error in xml document is , like which line and column.
How should i do this ? any suggestions?
You are closing your 'age' tag like this
<age>35<age/>
It should be like
<age>35</age>
hope this works for you.
Firstly, you have not specified how you are parsing your XML in c#. It matters.
Now as for validity of your XML document, a valid xml document should have these:
XML documents must have a root element
XML elements must have a closing tag
XML tags are case sensitive
XML elements must be properly nested
-XML attribute values must be quoted
now try adding this to the top of your xml doc
<?xml version="1.0" encoding="ISO-8859-1"?>
Now, to parse XML document, you can use either XmlDocument class or Linq's XDocument class.
Lets take example of XmlDocument.
if you have a xml string, load Xml as below:
XmlDocument doc = new XmlDocument();
doc.LoadXml(stringXML);
foreach(XmlNode node in doc.SelectNodes("xml/person/salary"))
{
var strSalary = node.InnerText;
var intSalary = Convert.ToInt32(strSalary??0);
}
if you have a xml file, load Xml as below:
XmlDocument doc = new XmlDocument();
doc.Load(XMLFilePath);
Full example:
string xml = #"<xml>
<person name=""a"">
<age>21</age>
<salary>50000</salary>
</person>
<person name=""b"">
<age>25</age>
<salary>30000</salary>
</person>
<person name=""c"">
<age>30</age>
<salary>60000</salary>
</person>
<person name=""d"">
<age>35</age>
<salary>150000</salary>
</person>
</xml>";
using (var sr = new StringReader(xml))
{
var xml2 = XDocument.Load(sr, LoadOptions.SetLineInfo);
foreach (var person in xml2.Root.Elements())
{
//string name = (string)person.Attribute("name"); // Unused
int age = (int)person.Element("age");
int salary = (int)person.Element("salary");
// Your check
bool error = salary > 50000 && age > 30;
if (error)
{
// IMPORTANT PART HERE!!!
int lineNumber = -1;
int colNumber = -1;
var lineInfo = (IXmlLineInfo)person;
if (lineInfo.HasLineInfo())
{
lineNumber = lineInfo.LineNumber;
colNumber = lineInfo.LinePosition;
}
return string.Format("Error on line {0}, col {1}", lineNumber, colNumber);
// END IMPORTANT PART!!!
}
}
}
The "trick" is that XElement implement IXmlLineInfo (as explained here), but you have to load the document with LoadOptions.SetLineInfo.
Related
I want all the blank lines to be removed in the XML below before writing it to document. It may help to know that I used the .DeleteSelf() method of the XPathNavigator class to get rid of the unwanted nodes before (and that only leaves empty lines).
<Person xmlns="http://someURI.com/something">
<FirstName>Name1</FirstName>
<MiddleName>Name2</MiddleName>
<LastName>Name3</LastName>
</Person>
I'd suggest to use XDocument class:
1. method:
string xcontent = #" strange xml content here ";
XDocument xdoc = XDocument.Parse(xcontent);
xdoc.Save("FullFileName.xml");
2. method:
XmlReader rdr = XmlReader.Create(new StringReader(xcontent));
XDocument xdoc = XDocument.Load(rdr);
xdoc.Save("FullFileName.xml");
returns:
<Person xmlns="http://someURI.com/something">
<FirstName>Name1</FirstName>
<MiddleName>Name2</MiddleName>
<LastName>Name3</LastName>
</Person>
Msdn documentation: https://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument%28v=vs.110%29.aspx
Can also do line by line reading and writing.
string line = string.Empty;
using (StreamReader file_r = new System.IO.StreamReader("HasBlankLines.xml"))
{
using (StreamWriter file_w = new System.IO.StreamWriter("NoBlankLines.xml"))
{
while ((line = file_r.ReadLine()) != null)
{
if (line.Trim().Length > 0)
file_w.WriteLine(line);
}
}
}
Outputs:
<Person xmlns="http://someURI.com/something">
<FirstName>Name1</FirstName>
<MiddleName>Name2</MiddleName>
<LastName>Name3</LastName>
</Person>
Using C#, I need to store all the data of the inner text of Email nodes into a list, and all the data of the inner text of Related nodes into a list for each person separately. For now I was only able to store only first "email" node and first "related" node into lists. I get this:
,when I should get this
.
How to get the right answer? This is my xml file:
<? xml version="1.0" encoding="utf-8"?>
<People>
<Person>
<Name>Toni</Name>
<Email>a#g.c</Email>
<Email>b#g.c</Email>
<Email>c#g.c</Email>
<Related>Friend1</Related>
<Related>Friend2</Related>
</Osoba>
<Osoba>
<Name>Deni</Name>
<Email>d#g.c</Email>
<Email>e#g.c</Email>
<Email>f#g.c</Email>
<Related>Friend3</Related>
<Related>Friend4</Related>
</Osoba>
</People>
I am assuming the following xml Instead of the one you posted since it is wrong.
<?xml version="1.0" encoding="utf-8"?>
<People>
<Person>
<Name>Toni</Name>
<Email>a#g.c</Email>
<Email>b#g.c</Email>
<Email>c#g.c</Email>
<Related>Friend1</Related>
<Related>Friend2</Related>
</Person>
<Person>
<Name>Deni</Name>
<Email>d#g.c</Email>
<Email>e#g.c</Email>
<Email>f#g.c</Email>
<Related>Friend3</Related>
<Related>Friend4</Related>
</Person>
</People>
I am using LINQ to XML.(Another way is to use XmlDocument)
String path = "Path of your xml file";
XDocument doc = XDocument.Load(path);
var nodes = doc.Descendants("Person");
foreach (XElement node in nodes)
{
var name = node.Element("Name").Value;
var emails = node.Elements("Email").Select(x => x.Value);
}
So I have a program that reads all the name nodes in a XML file and adds these to a Combo Box. On a button click, it then takes this response and needs to get all the other data from the child nodes of the node the name is in.
The XML document:
<People>
<Person>
<Name>Greg</Name>
<Age>23</Age>
<Height>200</Height>
</Person>
<Person>
<Name>John</Name>
<Age>34</Age>
<Height>230</Height>
</Person>
</People>
What I've got so far:
XmlDocument Doc = new XmlDocument();
Doc.Load(FilePath);
foreach (XmlNode Node in Doc.SelectNodes("People/Person"))
{
comboBox1.Items.Add(Node.SelectSingleNode("Name").InnerText);
}
string RegPicked = comboBox1.SelectedItem.ToString();
foreach (XmlNode xNode in Doc.SelectNodes("People/Person"))
if (xNode.SelectSingleNode("Name").InnerText == RegPicked)
{
textBox1.Text = xNode.ParentNode.ChildNodes.ToString();
}
Doc.Save(FilePath);
When I run the code I just get "System.Xml.XmlChildNodes" in the text box.
I know I've done something wrong but I'm not sure what.
you have to distinguished child node:
textBox1.Text = xNode.ParentNode.ChildNodes.SelectSingleNode("age").InnerText;
Do this, you will get all the elements inside the parent of the node you are searching the value of.
string str = #"<People>
<Person>
<Name>Greg</Name>
<Age>23</Age>
<Height>200</Height>
</Person>
<Person>
<Name>John</Name>
<Age>34</Age>
<Height>230</Height>
</Person>
</People>";
XDocument xdoc = XDocument.Parse(str);
var xmlURL = (from el in xdoc.Descendants("Name")
where el.Value == "John"
select el.Parent).First().ToString();
I am trying to find a node in my xml file but getting the error ( see title)?
// instantiate XmlDocument and load XML from file
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\temp\test2.xml");
var node = doc.SelectSingleNode("/Offers/Offer/ID=[text()='1']");
var test = node;
xml
<?xml version="1.0" encoding="utf-8"?>
<Offers>
<Offer>
<Model>AAAA</Model>
<ID>1</ID>
<Name>First offer</Name>
</Offer>
<Offer>
<Model>BBBB</Model>
<ID>2</ID>
<Name>Second offer</Name>
</Offer>
</Offers>
Remove the = after ID:
var node = doc.SelectSingleNode("/Offers/Offer/ID=[text()='1']");
becomes:
var node = doc.SelectSingleNode("/Offers/Offer/ID[text()='1']");
I'm trying to find an easy and slick way to do the following requirement.
I have a XML message with this arrangement:
<persons>
<person>
<firstName>Mike</firstName>
<middleName>K.</middleName>
<lastName>Kelly</lastName>
</person>
<person>
<firstName>Steve</firstName>
<lastName>David</lastName>
</person>
<person>
<firstName>Laura</firstName>
<middleName>X.</middleName>
<lastName>Xavier</lastName>
</person>
</persons>
I want to parse this XML using xPath expressions.
persons/person/firstName
persons/person/middleName
persons/person/lastName
My objective is store firstName, middleName and lastName tag values like this into a list of string objects like this:
firstNameList[0] = "Mike";
firstNameList[1] = "Steve";
firstNameList[2] = "Laura";
middleNameList[0] = "K.";
middleNameList[1] = null;
middleNameList[2] = "X.";
lastNameList[0] = "Kelly";
lastNameList[1] = "David";
lastNameList[2] = "Xavier";
In my C# code, I do this:
XmlNodeList firstNameNodeList = xmlDoc.SelectNodes("persons/person/firstName", nsmgr);
XmlNodeList middleNameNodeList = xmlDoc.SelectNodes("persons/person/middleName", nsmgr);
XmlNodeList lastNameNodeList = xmlDoc.SelectNodes("persons/person/lastName", nsmgr);
The problem with this code is that for middle name, I don't have it for 2nd person in my XML list. So the middleNameNodeList returns 2 values (K. and X.) but I wouldn't know whether the 1st or 2nd or 3rd person's middle name is missing.
I was hoping that SelectNodes() API would provide an iteration or index ID as which repeating element has a given value.
Please suggest me an easiest way to achieve what I needed? Thanks so much for your help, JK
How about this?
foreach (Node person in xmlDoc.SelectNodes("persons/person", nsmgr))
{
firstNameNodeList.Add(person.SelectSingleNode("firstName", nsmgr));
middleNameNodeList.Add(person.SelectSingleNode("middleName", nsmgr));
lastNameNodeList.Add(person.SelectSingleNode("lastName", nsmgr));
}
Intead of getting a list of names, try getting a list of persons, then iterate the list and get their names.
You just have to iterate over persons/person and handle each individually - this would work:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"test.xml");
var persons = xmlDoc.SelectNodes("persons/person");
foreach (XmlNode person in persons)
{
string firstName = person.SelectSingleNode("firstName").InnerText;
string middleName = (person.SelectSingleNode("middleName") != null)
? person.SelectSingleNode("middleName").InnerText
: null;
string lastName = person.SelectSingleNode("lastName").InnerText;
}
Try
<persons>
<person>
<firstName>Mike</firstName>
<middleName>K.</middleName>
<lastName>Kelly</lastName>
</person>
<person>
<firstName>Steve</firstName>
<middleName />
<lastName>David</lastName>
</person>
<person>
<firstName>Laura</firstName>
<middleName>X.</middleName>
<lastName>Xavier</lastName>
</person>
</persons>
<person>
<firstName>Steve</firstName>
<middleName />
<lastName>David</lastName>
</person>
this should return "K","","X" for InnnerText