I need to parse the following xml code in c# using system.xml. I need a list of strings containing the content of the tags User.
<Configuration>
....
<DebugUsersMail>
<User>bob#example.com</User>
<User>lenny#example.com</User>
</DebugUsersMail>
...
</Configuration>
If you can use Linq something like this is nice and simple
XDocument xmlDoc = XDocument.Load("C:\\your_xml_file.xml");
List<string> users = xmlDoc.Descendants("User").Select(xElem => (string)xElem).ToList();
You'll need to include a reference to System.Xml.Linq in your using statements to use the XDocument object.
This does however assume that there are no other User elements in the xml file that you don't want included in the list.
If you want to be more specific you could do this
List<string> users = xmlDoc.Descendants("DebugUsersMail")
.Descendants("User").Select(xElem => (string)xElem).ToList();
I found a solution:
List<string> returnList = new List<string>();
XmlNodeList node = xmlDocument.GetElementsByTagName("DebugUsersMail");
XmlNodeList childNodes = node[0].ChildNodes;
for(int i = 0; i < childNodes.Count; i++)
{
returnList.Add(childNodes[i].InnerText);
}
return returnList;
There are tons of ways to do it in C#. You can use:
XmlDocument andthen XPath and XQuery
XDocument and Linq
XmlTextReader/SAX
Regular expressions
Deserialise the XML to objects
The route to take depends a lot of what the rest of XML looks like.
Related
How can I read an XML attribute using C#'s XmlDocument?
I have an XML file which looks somewhat like this:
<?xml version="1.0" encoding="utf-8" ?>
<MyConfiguration xmlns="http://tempuri.org/myOwnSchema.xsd" SuperNumber="1" SuperString="whipcream">
<Other stuff />
</MyConfiguration>
How would I read the XML attributes SuperNumber and SuperString?
Currently I'm using XmlDocument, and I get the values in between using XmlDocument's GetElementsByTagName() and that works really well. I just can't figure out how to get the attributes?
XmlNodeList elemList = doc.GetElementsByTagName(...);
for (int i = 0; i < elemList.Count; i++)
{
string attrVal = elemList[i].Attributes["SuperString"].Value;
}
You should look into XPath. Once you start using it, you'll find its a lot more efficient and easier to code than iterating through lists. It also lets you directly get the things you want.
Then the code would be something similar to
string attrVal = doc.SelectSingleNode("/MyConfiguration/#SuperNumber").Value;
Note that XPath 3.0 became a W3C Recommendation on April 8, 2014.
You can migrate to XDocument instead of XmlDocument and then use Linq if you prefer that syntax. Something like:
var q = (from myConfig in xDoc.Elements("MyConfiguration")
select myConfig.Attribute("SuperString").Value)
.First();
I have an Xml File books.xml
<ParameterDBConfig>
<ID Definition="1" />
</ParameterDBConfig>
Program:
XmlDocument doc = new XmlDocument();
doc.Load("D:/siva/books.xml");
XmlNodeList elemList = doc.GetElementsByTagName("ID");
for (int i = 0; i < elemList.Count; i++)
{
string attrVal = elemList[i].Attributes["Definition"].Value;
}
Now, attrVal has the value of ID.
XmlDocument.Attributes perhaps? (Which has a method GetNamedItem that will presumably do what you want, although I've always just iterated the attribute collection)
Assuming your example document is in the string variable doc
> XDocument.Parse(doc).Root.Attribute("SuperNumber")
1
If your XML contains namespaces, then you can do the following in order to obtain the value of an attribute:
var xmlDoc = new XmlDocument();
// content is your XML as string
xmlDoc.LoadXml(content);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
// make sure the namespace identifier, URN in this case, matches what you have in your XML
nsmgr.AddNamespace("ns", "urn:oasis:names:tc:SAML:2.0:protocol");
// get the value of Destination attribute from within the Response node with a prefix who's identifier is "urn:oasis:names:tc:SAML:2.0:protocol" using XPath
var str = xmlDoc.SelectSingleNode("/ns:Response/#Destination", nsmgr);
if (str != null)
{
Console.WriteLine(str.Value);
}
More on XML namespaces here and here.
Please could someone help me? I have researched other posts (such as efficiently removing duplicate xml elements in c#) on how to remove duplicates in XML using c# and altered them to solve my problem all to no avail. I'm not very experienced in XML and all I wish to do is remove the duplicates from the following XML.
I've inherited this code and can't change the structure.
Many thanks to anyone that can help.
<Request>
<Type>Delete</Type>
<Client>
<ClientId></ClientId>
<Assignment>
<AssignmentId></AssignmentId>
<Assessments>
<AssessmentId>664449ba-21b9-e511-999d-d8fc934939fe</AssessmentId>
<AssessmentId>5ea8edd4-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>5ea8edd4-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>865a13f8-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>865a13f8-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>06439800-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>06439800-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>f683aa08-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>f683aa08-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>063f8012-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>063f8012-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>16f7c329-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>16f7c329-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>76706838-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>76706838-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>86194741-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>86194741-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>66cf984f-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>66cf984f-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
</Assessments>
</Assignment>
</Client>
</Request>
If you can change the application building the XML (it sounds ilke you can't), my preferred method would be to use a HashSet<string> to build up the Asssesments collection. If it's coming off a SQL query, use DISTINCT or GROUP BY.
If you're working with the XML itself and really just have no way to change it, LINQ to XML should work with a custom IEqualityComparer should work:
string xml = #"<Request>
<Type>Delete</Type>
<Client>
<ClientId></ClientId>
<Assignment>
<AssignmentId></AssignmentId>
<Assessments>
<AssessmentId>664449ba-21b9-e511-999d-d8fc934939fe</AssessmentId>
<AssessmentId>5ea8edd4-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>5ea8edd4-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>865a13f8-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>865a13f8-e1b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>06439800-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>06439800-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>f683aa08-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>f683aa08-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>063f8012-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>063f8012-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>16f7c329-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>16f7c329-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>76706838-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>76706838-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>86194741-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>86194741-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>66cf984f-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
<AssessmentId>66cf984f-e2b9-e511-9af1-d8fc934939fe</AssessmentId>
</Assessments>
</Assignment>
</Client>
</Request>";
XDocument xd = XDocument.Parse(xml);
var assessments = xd.Root.Element("Client")
.Element("Assignment")
.Element("Assessments");
// get the distinct ones
var distinctEls = assessments.Elements()
.Distinct(new XElComparer())
.ToList(); // ensure we actually get the list, not just the enumerator or elements we're about to remove
// remove all children
assessments.Elements().Remove();
// add back our distinct list
assessments.Add(distinctEls);
Console.WriteLine(xd);
Console.ReadKey();
and the XElComparer:
public class XElComparer : IEqualityComparer<XElement>
{
public bool Equals(XElement x, XElement y)
{
return x.Value.Equals(y.Value);
}
public int GetHashCode(XElement obj)
{
if (obj == null) return 0;
return obj.Value.GetHashCode();
}
}
I prefer to work with c# objects.
So, you can deserialize this xml to objects with xml serializer. Also you can generate c# classes by xml in visual studio: Edit-> PasteSpecial-> Paste xml as classes.
Your code will look like this:
Request request;
var fileName = "File1.xml";
//Parsing
var sr = new XmlSerializer(typeof(Request));
using (var fs = new FileStream(fileName, FileMode.Open))
{
request = (Request)sr.Deserialize(fs);
}
//Selecting distinct C# logic
var distinctAssignments = request.Client.Assignment.Assessments.Distinct();
request.Client.Assignment.Assessments = distinctAssignments.ToArray();
//Saving your document
var xmlDocument = new XmlDocument();
using (var stream = new MemoryStream())
{
sr.Serialize(stream, request);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(fileName);
stream.Close();
}
Also you can use XSLT but it will look bit complex - https://msdn.microsoft.com/en-us/library/bb399419(v=vs.110).aspx
You can do this with a simple (or not so simple I guess) XPath query.
XmlDocument doc = new XmlDocument();
doc.LoadFrom(xml); // xml in string form
var nodes = doc.SelectNodes("//AssessmentId[not(. = preceding-sibling::AssessmentId)]");
That will get you a list of unique assignment ID nodes which you can then use to remove all the existing nodes and add those. You could also remove the 'not' in the XPath query and then you would get a list of the duplicates which you could remove those nodes from the parent node as well.
This is my XML:
<?xml version="1.0"?>
<formatlist>
<format>
<formatName>WHC format</formatName>
<delCol>ID</delCol>
<delCol>CDRID</delCol>
<delCol>TGIN</delCol>
<delCol>IPIn</delCol>
<delCol>TGOUT</delCol>
<delCol>IPOut</delCol>
<srcNum>SRCNum</srcNum>
<distNum>DSTNum</distNum>
<connectTime>ConnectTime</connectTime>
<duration>Duration</duration>
</format>
<format>
<formatName existCombineCol="1">Umobile format</formatName> //this format
<delCol>billing_operator</delCol>
<hideCol>event_start_date</hideCol>
<hideCol>event_start_time</hideCol>
<afCombineName dateType="DateTime" format="dd/MM/yyyy HH:mm:ss"> //node i want
<name>ConnectdateTimeAFcombine</name>
<combineDate>event_start_date</combineDate>
<combineTime>event_start_time</combineTime>
</afCombineName>
<afCombineName dateType="DateTime" format="dd/MM/yyyy HH:mm:ss"> //node i want
<name>aaa</name>
<combineDate>bbb</combineDate>
<combineTime>ccc</combineTime>
</afCombineName>
<modifyPerfixCol action="add" perfix="60">bnum</modifyPerfixCol>
<srcNum>anum</srcNum>
<distNum>bnum</distNum>
<connectTime>ConnectdateTimeAFcombine</connectTime>
<duration>event_duration</duration>
</format>
</formatlist>
I want to find format with Umobile format then iterate over those two nodes.
<afCombineName dateType="DateTime" format="dd/MM/yyyy HH:mm:ss"> //node i want
<name>ConnectdateTimeAFcombine</name>
<combineDate>event_start_date</combineDate>
<combineTime>event_start_time</combineTime>
</afCombineName>
<afCombineName dateType="DateTime" format="dd/MM/yyyy HH:mm:ss"> //node i want
<name>aaa</name>
<combineDate>bbb</combineDate>
<combineTime>ccc</combineTime>
</afCombineName>
and list all the two node's child nodes. The result should like this:
ConnectdateTimeAFcombine,event_start_date,event_start_time.
aaa,bbb,ccc
How can I do this?
foreach(var children in format.Descendants())
{
//Do something with the child nodes of format.
}
For all XML related traversing, you should get used to using XPath expressions. It is very useful. Even if you could perhaps do something easier in your specific case, it is good practice to use XPath. This way, if your scheme changes at some point, you just update your XPath expression and your code will be up and running.
For a complete example, you can have a look at this article.
You can use the System.Xml namespace APIs along with System.Xml.XPath namespace API. Here is a quick algorithm that will help you do your task:
Fetch the text node containing the string Umobile format using the below XPATH:
XmlNode umobileFormatNameNode = document.SelectSingleNode("//formatName[text()='Umobile format']");
Now the parent of umobileFormatNameNode will be the node that you are interested in:
XmlNode formatNode = umobileFormatNameNode.ParentNode;
Now get the children for this node:
XmlNodeList afCombineFormatNodes = formatNode.SelectNodes("afCombineName");
You can now process the list of afCombineFormatNodes
for(XmlNode xmlNode in afCombineNameFormtNodes)
{
//process nodes
}
This way you can access those elements:
var doc = System.Xml.Linq.XDocument.Load("PATH TO YOUR XML FILE");
var result = doc.Descendants("format")
.Where(x => (string)x.Element("formatName") == "Umobile format")
.Select(x => x.Element("afCombineName"));
Then you can iterate the result this way:
foreach (var item in result)
{
string format = item.Attribute("format").Value.ToString();
string name = item.Element("name").Value.ToString();
string combineDate = item.Element("combineDate").Value.ToString();
string combineTime = item.Element("combineTime").Value.ToString();
}
I have a request that returns a large xml file. I have the file in a XmlDocument type in my application. From that Doc how can I read an element like this:
<gphoto:videostatus>final</gphoto:videostatus>
I would like to pull that value final from that element. Also If i have multiple elements as well, can I pull that into a list? thanks for any advice.
If you already have an XmlDocument then you can use the function GetElementsByTagName() to create an XmlNodeList that can be accessed similar to an array.
http://msdn.microsoft.com/en-us/library/dc0c9ekk.aspx
//Create the XmlDocument.
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
//Display all the book titles.
XmlNodeList elemList = doc.GetElementsByTagName("title");
for (int i=0; i < elemList.Count; i++)
{
Console.WriteLine(elemList[i].InnerXml);
}
You can select nodes using XPath and SelectSingleNode SelectNodes. Look at http://www.codeproject.com/Articles/9494/Manipulate-XML-data-with-XPath-and-XmlDocument-C for examples. Then you can use for example InnerText to get final. Maybe you need to work with namespaces (gphoto). The //videostatus would select all videostatus elements
You can try using LINQ
XNamespace ns = XNamespace.Get(""); //use the xmnls namespace here
XElement element = XElement.Load(""); // xml file path
var result = element.Descendants(ns + "videostatus")
.Select(o =>o.Value).ToList();
foreach(var values in value)
{
}
Thanks
Deepu
I have several XML files that I wish to read attributes from. My main objective is to apply syntax highlighting to rich text box.
For example in one of my XML docs I have: <Keyword name="using">[..] All the files have the same element: Keyword.
So, how can I get the value for the attribute name and put them in a collection of strings for each XML file.
I am using Visual C# 2008.
The other answers will do the job - but the syntax highlighting thingy and the several xml files you say you have makes me thinks you need something faster, why not use a lean and mean XmlReader?
private string[] getNames(string fileName)
{
XmlReader xmlReader = XmlReader.Create(fileName);
List<string> names = new List<string>();
while (xmlReader.Read())
{
//keep reading until we see your element
if (xmlReader.Name.Equals("Keyword") && (xmlReader.NodeType == XmlNodeType.Element))
{
// get attribute from the Xml element here
string name = xmlReader.GetAttribute("name");
// --> now **add to collection** - or whatever
names.Add(name);
}
}
return names.ToArray();
}
Another good option would be the XPathNavigator class - which is faster than XmlDoc and you can use XPath.
Also I would suggest to go with this approach only IFF after you try with the straightforward options you're not happy with performance.
You could use XPath to get all the elements, then a LINQ query to get the values on all the name atttributes you find:
XDocument doc = yourDocument;
var nodes = from element in doc.XPathSelectElements("//Keyword")
let att = element.Attribute("name")
where att != null
select att.Value;
string[] names = nodes.ToArray();
The //Keyword XPath expression means, "all elements in the document, named "Keyword".
Edit: Just saw that you only want elements named Keyword. Updated the code sample.
Like others, I would suggest using LINQ to XML - but I don't think there's much need to use XPath here. Here's a simple method to return all the keyword names within a file:
static IEnumerable<string> GetKeywordNames(string file)
{
return XDocument.Load(file)
.Descendants("Keyword")
.Attributes("name")
.Select(attr => attr.Value);
}
Nice and declarative :)
Note that if you're going to want to use the result more than once, you should call ToList() or ToArray() on it, otherwise it'll reload the file each time. Of course you could change the method to return List<string> or string[] by -adding the relevant call to the end of the chain of method calls, e.g.
static List<string> GetKeywordNames(string file)
{
return XDocument.Load(file)
.Descendants("Keyword")
.Attributes("name")
.Select(attr => attr.Value)
.ToList();
}
Also note that this just gives you the names - I would have expected you to want the other details of the elements, in which case you'd probably want something slightly different. If it turns out you need more, please let us know.
You could use LINQ to XML.
Example:
var xmlFile = XDocument.Load(someFile);
var query = from item in xmlFile.Descendants("childobject")
where !String.IsNullOrEmpty(item.Attribute("using")
select new
{
AttributeValue = item.Attribute("using").Value
};
You'll likely want to use XPath. //Keyword/#name should get you all of the keyword names.
Here's a good introduction: .Net and XML XPath Queries
**<Countries>
<Country name ="ANDORRA">
<state>Andorra (general)</state>
<state>Andorra</state>
</Country>
<Country name ="United Arab Emirates">
<state>Abu Z¸aby</state>
<state>Umm al Qaywayn</state>
</Country>**
public void datass(string file)
{
string file = HttpContext.Current.Server.MapPath("~/App_Data/CS.xml");
XmlDocument doc = new XmlDocument();
if (System.IO.File.Exists(file))
{
//Load the XML File
doc.Load(file);
}
//Get the root element
XmlElement root = doc.DocumentElement;
XmlNodeList subroot = root.SelectNodes("Country");
for (int i = 0; i < subroot.Count; i++)
{
XmlNode elem = subroot.Item(i);
string attrVal = elem.Attributes["name"].Value;
Response.Write(attrVal);
XmlNodeList sub = elem.SelectNodes("state");
for (int j = 0; j < sub.Count; j++)
{
XmlNode elem1 = sub.Item(j);
Response.Write(elem1.InnerText);
}
}
}