C# cannot get values from list of objects - c#

I have my main Program class that calls the StronyElementuStrukt procedure
List<object> monthlyPages = new List<object>();
monthlyPages = StronyElementuStrukt(loginGuid, "8B35134E10A8432DB1A8C06A58427988");
Here is the procedure - a method that builds a list of xml nodes and returns it to the main Program class:
public static List<object> StronyElementuStrukt(string LoginGUID, string LinkGUID)
{
List<object> listPages = new List<object>();
XmlDocument document = new XmlDocument(); // tworzenie nowego obiektu - dokument xml z odpowiedzia serwera
document.LoadXml(response.Result); //wczytywanie xmla z odpowiedzia serwera do obiektu
XmlNode pageNode = document.SelectSingleNode("/IODATA/PAGES/PAGE"); //deklaracja noda xmlowego
if (pageNode != null) //jeżeli PAGE node istnieje
{
XmlNodeList nodeList = document.SelectNodes("//PAGE");
foreach (XmlNode node in nodeList)
{
listPages.Add(node);
}
return listPages;
}
}
In the main Program Class I need to pick up value of xml id attribute, I'm trying to do it like this:
foreach (object monthlyPage in monthlyPages)
{
Console.WriteLine(monthlyPage.Attributes["id"].Value);
}
The problem is that when I try to get the id I get the following error:
Error 6 'object' does not contain a definition for 'Attributes' and no
extension method 'Attributes' accepting a first argument of type
'object' could be found (are you missing a using directive or an
assembly reference?)
Could you tell me how to reach to xml attributes in the foreach loop, please? Please ask if something is not clear enough.

Change the method to return a List<XmlNode>.
public static List<XmlNode> StronyElementuStrukt(string LoginGUID, string LinkGUID)
{
List<XmlNode> listPages = new List<object>();
XmlDocument document = new XmlDocument(); // tworzenie nowego obiektu - dokument xml z odpowiedzia serwera
document.LoadXml(response.Result); //wczytywanie xmla z odpowiedzia serwera do obiektu
XmlNode pageNode = document.SelectSingleNode("/IODATA/PAGES/PAGE"); //deklaracja noda xmlowego
if (pageNode != null) //jeżeli PAGE node istnieje
{
XmlNodeList nodeList = document.SelectNodes("//PAGE");
foreach (XmlNode node in nodeList)
{
listPages.Add(node);
}
}
return listPages;
}
Then this will work.
List<XmlNode> monthlyPages = StronyElementuStrukt(
loginGuid,
"8B35134E10A8432DB1A8C06A58427988");
foreach (XmlNode monthlyPage in monthlyPages)
{
Console.WriteLine(monthlyPage.Attributes["id"].Value);
}
Note that you could just change the foreach to declare monthlyPage as XmlNode instead of object and it will do a cast for you. But it is better to be specific with the types you are putting into a generic collection.

I changed all occurences from List<object> to List<XmlNode>. So the code now looks like this:
Main Program:
List<XmlNode> monthlyPages = new List<XmlNode>();
monthlyPages = StronyElementuStrukt(loginGuid, "8B35134E10A8432DB1A8C06A58427988");
foreach (XmlNodemonthlyPage in monthlyPages)
{
Console.WriteLine(monthlyPage.Attributes["id"].Value);
}
Procedure:
public static List<XmlNode> StronyElementuStrukt(string LoginGUID, string LinkGUID)
{
List<XmlNode> listPages = new List<XmlNode>();
XmlDocument document = new XmlDocument(); // tworzenie nowego obiektu - dokument xml z odpowiedzia serwera
document.LoadXml(response.Result); //wczytywanie xmla z odpowiedzia serwera do obiektu
XmlNode pageNode = document.SelectSingleNode("/IODATA/PAGES/PAGE"); //deklaracja noda xmlowego
if (pageNode != null) //jeżeli PAGE node istnieje
{
XmlNodeList nodeList = document.SelectNodes("//PAGE");
foreach (XmlNode node in nodeList)
{
listPages.Add(node);
}
return listPages;
}
}

Related

How to hold more than one values in XML element?

xWaarde.Value is overriding with new values and flushing old values.
how to stored multiple values in Xelement.
private XElement[] AddCoordinatenList(XElement childElements)
{
XmlNode xmlCoordinatenNode = Utility.GetMappingValues(Constants.BMCoordinaten, ConnectionType.BM);
XmlNode xWaardeNode = Utility.GetMappingValues(Constants.BMXwaarde, ConnectionType.BM);
XmlNode yWaardeNode = Utility.GetMappingValues(Constants.BMYwaarde, ConnectionType.BM);
XmlNode CoordinateX = Utility.GetMappingValues(Constants.XCoordinate, ConnectionType.BM);
XmlNode CoordinateY = Utility.GetMappingValues(Constants.YCoordinate, ConnectionType.BM);
var coordinatenList = from document in childElements.DescendantsAndSelf() where document.Name.LocalName == xmlCoordinatenNode.Name select document;
List<XElement> xcoordinatenList = new List<XElement>();
XElement xWaarde = new XElement(CoordinateX.Name);
XElement yWaarde = new XElement(CoordinateY.Name);
if (coordinatenList.Count() > 0)
{
foreach (XElement element in coordinatenList.Descendants())
{
if (element.Name.LocalName == xWaardeNode.Name)
{
xWaarde.Value = element.Value;
}
if (element.Name.LocalName == yWaardeNode.Name)
{
yWaarde.Value = element.Value;
}
}
}
return xcoordinatenList.ToArray();
}
It's not possible. Use Attributes:
XAttribute attribute = new XAttribute("name1", <value>);
element.Add(attribute);
attribute = new XAttribute("name2", <value>);
element.Add(attribute);
You can also add a list of child elements or add all strings as one string, separated by a comma for instance.

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")

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;
});
}
});
}
});

using xmldocument to read xml

<?xml version="1.0" encoding="utf-8" ?>
<testcase>
<date>4/12/13</date>
<name>Mrinal</name>
<subject>xmlTest</subject>
</testcase>
I am trying to read the above xml using c#, But i get null exception in the try catch block can any body suggest the required change.
static void Main(string[] args)
{
XmlDocument xd = new XmlDocument();
xd.Load("C:/Users/mkumar/Documents/testcase.xml");
XmlNodeList nodelist = xd.SelectNodes("/testcase"); // get all <testcase> nodes
foreach (XmlNode node in nodelist) // for each <testcase> node
{
CommonLib.TestCase tc = new CommonLib.TestCase();
try
{
tc.name = node.Attributes.GetNamedItem("date").Value;
tc.date = node.Attributes.GetNamedItem("name").Value;
tc.sub = node.Attributes.GetNamedItem("subject").Value;
}
catch (Exception e)
{
MessageBox.Show("Error in reading XML", "xmlError", MessageBoxButtons.OK);
}
........
.....
The testcase element has no attributes. You should be looking to it's child nodes:
tc.name = node.SelectSingleNode("name").InnerText;
tc.date = node.SelectSingleNode("date").InnerText;
tc.sub = node.SelectSingleNode("subject").InnerText;
You might process all nodes like this:
var testCases = nodelist
.Cast<XmlNode>()
.Select(x => new CommonLib.TestCase()
{
name = x.SelectSingleNode("name").InnerText,
date = x.SelectSingleNode("date").InnerText,
sub = x.SelectSingleNode("subject").InnerText
})
.ToList();
You can use LINQ to XML to select all testcase elements from your xml and parse them to TestCase instances:
var xdoc = XDocument.Load("C:/Users/mkumar/Documents/testcase.xml");
var testCases = from tc in xdoc.Descendants("testcase")
select new CommonLib.TestCase {
date = (string)tc.Element("date"),
name = (string)tc.Element("name"),
sub= (string)tc.Element("subject")
};
BTW you have only one testcase element currently, which is root of XML file. So, you can do instead:
var tc = XElement.Load("C:/Users/mkumar/Documents/testcase.xml");
var testCase = new CommonLib.TestCase {
date = (string)tc.Element("date"),
name = (string)tc.Element("name"),
sub= (string)tc.Element("subject")
};
private static void Main(string[] args)
{
XmlDocument xd = new XmlDocument();
xd.Load("C:\\test1.xml");
XmlNodeList nodelist = xd.SelectNodes("/testcase"); // get all <testcase> nodes
foreach (XmlNode node in nodelist) // for each <testcase> node
{
try
{
var name = node.SelectSingleNode("date").InnerText;
var date = node.Attributes.GetNamedItem("name").Value;
var sub = node.Attributes.GetNamedItem("subject").Value;
}
catch (Exception e)
{
MessageBox.Show("Error in reading XML", "xmlError", MessageBoxButtons.OK);
}
}
This will work I have test it #Alex correct answer
You are trying to read attributes whereas date, name and subject are not attributes. They are subnodes.
your code should be like this
XmlDocument xd = new XmlDocument();
xd.Load("test.xml");
XmlNodeList nodelist = xd.SelectNodes("/testcase"); // get all <testcase> nodes
foreach (XmlNode node in nodelist) // for each <testcase> node
{
try
{
string name = node.SelectSingleNode("name").InnerText;
string date = node.SelectSingleNode("date").InnerText;
string sub = node.SelectSingleNode("subject").InnerText;
}
catch (Exception ex)
{
MessageBox.Show("Error in reading XML", "xmlError", MessageBoxButtons.OK);
}
}
Your Xml do not contain Attributes. date, name and subject - it's Child Nodes of the testcase Node.
Try this:
...
tc.name = node["name"].InnerText;
...
or this:
...
tc.name = node.SelectSingleNode("name").InnerText;
...

Foreach loop XmlNodeList

Currently I have the following code:
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
foreach (int i in tweets)
{
if (tweets[i].InnerText.Length > 0)
{
MessageBox.Show(tweets[i].InnerText);
}
}
Which doesn't work, it gives me System.InvalidCastException on the foreach line.
The following code works perfectly (no foreach, the i is replaced with a zero):
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
if (tweets[0].InnerText.Length > 0)
{
MessageBox.Show(tweets[0].InnerText);
}
I know that there is already a marked answer, but you can do it like you did in your first try, you just need to replace the int with XmlNode
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
foreach (XmlNode i in tweets)
{
if (i.InnerText.Length > 0)
{
MessageBox.Show(i.InnerText);
}
}
tweets is a node list. I think that what you're trying to do is this:
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
for (int i = 0; i < tweets.Count; i++)
{
if (tweets[i].InnerText.Length > 0)
{
MessageBox.Show(tweets[i].InnerText);
}
}
It is not of Int type, That is the reason you are getting a casting exception. You can either replace int with the appropriate type or simply make use of type inference (implicitly typed variables) to handle this. Here i am using typeinference.by saying type as var, The compiler will understand it is of type of the iterator variable in tweets collection
foreach (var i in tweets)
{
if (i!=null)
{
string tweet= (((System.Xml.XmlElement)(i))).InnerText;
MessageBox.Show(tweet);
}
}
EDIT : With the Wonderful LINQtoXML, Your code can be rewritten like this.
string url = "http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter";
XElement elm = XElement.Load(url);
if (elm != null)
{
foreach (var status in elm.Elements("status"))
{
string tweet = status.Element("text").Value;
MessageBox.Show(ss);
}
}
All the answers seem to be a bit outdated Imperative examples so I will add a declarative one. This is not doing what the OP wanted but I'm sure you'll get the point.
public static List<System.Xml.XmlNode> toList(System.Xml.XmlNodeList nodelist){
List<System.Xml.XmlNode> nodes = new List<System.Xml.XmlNode>();
foreach (System.Xml.XmlNode node in nodelist)
{
nodes.Add(node);
}
return nodes;
}
public static ReadMeObject setXml(ReadMeObject readmeObject){
readmeObject.xmlDocument = new System.Xml.XmlDocument();
readmeObject.xmlDocument.LoadXml("<body>"+readmeObject.htmlStringContent+"</body>");
System.Xml.XmlNodeList images = readmeObject.xmlDocument.SelectNodes("//img");
Array.ForEach(
Functions.toList( images )
.Where((image) => image.Attributes != null)
.Where((image) => image.Attributes["src"] != null)
.Where((image) => image.Attributes["src"].Value != "")
.ToArray()
, (image) => {
Console.WriteLine(image.Attributes["src"].Value);
}
);
return readmeObject;
}
foreach (XmlNode node in tweets)
{
if (tweets[i].InnerText.Length > 0)
{
MessageBox.Show(tweets[node].InnerText);
}
}
I've changed the 'I', which you cannot use, to XmlNode, which selects a single line of your list.
You can loop through the Collection with .GetEnumerator()
this code is taken Microsoft Documentation :
XmlNodeList elemList = root.GetElementsByTagName("title");
IEnumerator ienum = elemList.GetEnumerator();
while (ienum.MoveNext()) {
XmlNode title = (XmlNode) ienum.Current;
Console.WriteLine(title.InnerText);
}
Use this simple extension method to iterate through XmlNodeList:
public static void ForEachXml<TXmlNode>(this XmlNodeList nodeList, Action<TXmlNode> action)
{
foreach (TXmlNode node in nodeList) action(node);
}
Method Call:
xDoc.GetElementsByTagName("text").ForEachXML<XmlNode>(tweet =>
{
if (tweet.InnerText.Length > 0)
MessageBox.Show(tweet.InnerText);
});

Categories