This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use LINQ to read all nodes from XML
I am trying to read an XML file using Linq in C# windows application. The sample of the xml string is given below.
<Root>
<Name>John Doe</Name>
<Data>FBCCF14D504B7B2DBCB5A5BDA75BD93B</Data>
<customer>true</customer>
<Accounts>1</Accounts>
<dataSet>
<Type1>Found matching records.</Type1>
<Type2>No matches found.</Type2>
<Type3>Found matching records.</Type3>
</dataSet>
</Root>
I want to display all the data inside the <dataset> tag and <datatag> i want to read <customer> tag as well.
I have created a class with members (string type, string status). Where in type i want to store the type1, 2...and in status i want to store what is inside the type node.
I am able to accomplish this but in the code i have to give
type1 = (string)row.Element("type1"),
type2=(string)row.Element("type2"),
i want to have a generic code in which i dont have to mention every type. In other words i want to read all the child nodes of tag whithout mentioning the tag name. I have spent 2 hours searching for this on google, but haven't found anything yet.
Expected output
save the information in class object (type and status).
And i want to read the customer tag so that i can know whether the person is already a customer
Any help will be very much appreciated.
Thanks
Update
According to inputs received from Raphaƫl Althaus
I have the following code:
var list = xml.Descendants("dataSet").Elements()
.Select(m => new CustomerInfo
{
Type = m.Name.LocalName,
Value = m.Value
}).ToList();
foreach (CustomerInfo item in list)
{
MessageBox.Show(item.Type+ " "+item.Value);
}
and for reading the Customer tag i have written more code.
var isCustomer = from customer in xmlDoc.Descendants("Root")
select new
{
customer = tutorial.Element("customer").Value,
}
Can i do both in one query?. Or this method is not so heavy on performance, so i can use this?
something like that ?
var q = xml.Descendants("dataSet").Elements()
.Select(m => new
{
type = m.Name.LocalName,
value = m.Value
}).ToList();
You can also directly populate a list of your "class with members"
var list = xml.Descendants("dataSet").Elements()
.Select(m => new <TheNameOfYourClass>
{
Type = m.Name.LocalName,
Value = m.Value
}).ToList();
EDIT :
to get the "customer" value, I would do another query
var customerElement = xml.Element("customer");
var isCustomer = customerElement != null && customerElement.Value == "true";
So you could mix all of that it in a little function
public IList<YourClass> ParseCustomers(string xmlPath, out isCustomer) {
var xml = XElement.Load(xmlPath);
var customerElement = xml.Element("customer");
isCustomer = customerElement != null && customerElement.Value == "true";
return xml.Descendants("dataSet").Elements()
.Select(m => new <YourClass>
{
Type = m.Name.LocalName,
Value = m.Value
}).ToList();
}
Related
I apologize because I'm still in the processes of learning Linq and HtmlAgilityPack, but I'm trying to assign Title and Link to already created string values. In other words, how do I access the values of this .ToList()?
Below is my code:
string imgTitle;
string imgLink;
private void getCaption(string txt)
{
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml("<html><head></head><body>" + txt + "</body></html>");
if (htmlDoc != null)
{
var elements = htmlDoc.DocumentNode.SelectNodes(#"//img[#src]").Select(img => new
{
Link = img.Attributes["src"].Value,
Title = img.Attributes["alt"].Value
}).ToList();
}
imgTitle = elements[0]["Title"]; //I thought i could do this
Sorry for a stupid question but I haven't seen any good explanation out there as to How Linq works and the ToList function. When I print elements[0] I get both values like this, {Link = www.link.url, Title = Some title}
imgTitle = elements[0].Title;
basically when you do
new
{
Link = img.Attributes["src"].Value,
Title = img.Attributes["alt"].Value
}
you are creating an anonymous object with 2 properties.
The list is a list of this anonymous object.
elements[0] gives you the first object. And you can access the 2 properties with elements[0].Link and elements[0].Title
What you really have in elements is a list of an anonymous type that have two properties, so you can access to the Title as follow:
imgTitle = elements[0].Title;
I'm having a problem with my XML document.
I want my program to find all values of the items in my XML file, but only if the handlingType is of a certain character bunch.
Code (C#) :
string path = "//files//handling.meta";
var doc = XDocument.Load(path);
var items = doc.Descendants("HandlingData").Elements("Item");
var query = from i in items
select new
{
HandlingName = (string)i.Element("handlingName"),
HandlingType = (string)i.Element("HandlingType"),
Mass = (decimal?)i.Element("fMass")
};
foreach (var HandlingType in items)
{
if (HandlingType.ToString() == "HANDLING_TYPE_FLYING")
{
MessageBox.Show(HandlingType.ToString());
}
}
The above code demonstraights a short version of what I want to happen, but fails to find this handlingType (does not show the messageBox)
Here's the XML :
<CHandlingDataMgr>
<HandlingData>
<Item type="CHandlingData">
<handlingName>Plane</handlingName>
<fMass value="380000.000000"/>
<handlingType>HANDLING_TYPE_FLYING</handlingType>
</Item>
<Item type="CHandlingData">
<handlingName>Car1</handlingName>
<fMass value="150000.000000"/>
<handlingType>HANDLING_TYPE_DRIVING</handlingType>
</Item>
</HandlingData>
</CHandlingDataMgr>
I would like the output to show the handlingName if it contains a certain HandlingType
For e.g.
if (handlingType == "HANDLING_TYPE_FLYING")
{
messageBox.Show(this.HandlingName);
}
My problem in short : Program does not find item's handling type, it does find the tag but when asked to display, returns empty/shows as nothing.
Edit: Also in the XML handling_type_flying contains extra elements such as thrust that cannot be found in each item (such as car), I would like the program to also find these elements. (this is a second problem I'm facing, maybe should ask 2nd ques?)
Several things that need fixing.
you are not using your query in your foreach loop. foreach (var item in query)
Your element has an upercase "H" but should be lowercase "handlingType". HandlingType = (string)i.Element("handlingType"),
You are not pulling the Attribute value of your fMass element.Mass = i.Element("fMass").Attribute("value").Value
Once you adjust your Query in your foreach loop you then need to adjust the loop to account for looping over your newly made object.
NOTE that I removed (decimal) from Mass = i.Element("fMass").Attribute("value").Value
here is the code with all the fixes.
class Program
{
static void Main()
{
const string path = "//files//handling.meta";
var doc = XDocument.Load(path);
var items = doc.Descendants("HandlingData").Elements("Item");
var query = from i in items
select new
{
HandlingName = (string)i.Element("handlingName"),
HandlingType = (string)i.Element("handlingType"),
Mass = i.Element("fMass").Attribute("value").Value
};
foreach (var item in query)
{
if (item.HandlingType == "HANDLING_TYPE_FLYING")
{
//Remove messagebox if consoleapp
MessageBox.Show(item.HandlingType);
MessageBox.Show(item.HandlingName);
Console.WriteLine(item.HandlingType);
Console.WriteLine(item.HandlingName);
}
}
}
}
I would recommend looking into serializing your xml to an object.
If you look at http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement(v=vs.110).aspx the ToString() method doesn't return the name of the tag, but the indented XML.
You should instead be using the Value property. Also you should use .equals("...") instead of ==
if (handlingType.Value.equals("HANDLING_TYPE_FLYING")
{
messageBox.Show(this.handlingname);
}
Please note that I'm new to C# and I learn it right now :) I couldn't find something similar to my problem, so I came here.
I have an application in which I add customers (it's in the final stage). All customers are stored in an XML file. Every single customer gets a new customer number. In my xml file I got an XmlNode called CustNo. Now if the user add a new customer and type in a number which already exist, it should pop up a message box to say that this number already exists. I got this c# code:
XDocument xdoc = XDocument.Load(path + "\\save.xml");
var xmlNodeExist = String.Format("Buchhaltung/Customers/CustNo");
var CustNoExist = xdoc.XPathSelectElement(xmlNodeExist);
if (CustNoExist != null)
{
MessageBox.Show("asdf");
}
And my XML file looks like this:
<Buchhaltung>
<Customers>
<CustNo>12</CustNo>
<Surname>Random</Surname>
<Forename>Name</Forename>
<Addr>Address</Addr>
<Zip>12345</Zip>
<Place>New York</Place>
<Phone>1234567890</Phone>
<Mail>example#test.com</Mail>
</Customers>
<Customers>
<CustNo>13</CustNo>
<Surname>Other</Surname>
<Forename>Forename</Forename>
<Addr>My Address</Addr>
<Zip>67890</Zip>
<Place>Manhattan</Place>
<Phone>0987654321</Phone>
<Mail>test#example.com</Mail>
</Customers>
</Buchhaltung>
But then the message box always pops up. What am I doing wrong?
That's because your XPath return all CustNo elements, no matter of it's content.
Try following:
var myNumber = 12;
var xmlNodeExist = String.Format("Buchhaltung/Customers/CustNo[. = {0}]", myNumber.ToString());
or using First and LINQ to XML:
var myNumber = 12;
var xmlNodeExist = "Buchhaltung/Customers/CustNo";
var CustNoExist = xdoc.XPathSelectElements(xmlNodeExist).FirstOrDefault(x => (int)x == myNumber);
You are currently testing for existance of any 'CustNo' element. See this reference about the XPath syntax.
Your XPath should say something like this:
Buchhaltung//Customers[CustNo='12']
which would say "any customers element containing a 'CustNo' element with value = '12'"
Combining that with your current code:
var custNoGivenByCustomer = "12";
var xmlNodeExistsXpath = String.Format("Buchhaltung//Customers[CustNo='{0}']", custNoGivenByCustomer );
var CustNoExist = xdoc.XPathSelectElement(xmlNodeExistsXpath);
You can use LINQ to XML
var number = textBox1.Text;
var CustNoExist = xdoc.Descendants("CustNo").Any(x => (string)x == number);
if(CustNoExist)
{
MessageBox.Show("asdf");
}
This is because you select the CustNo elements regardless of their value. This will filter it to the desired customer number:
int custNo = 12;
var xmlNodeExist = String.Format("Buchhaltung/Customers[CustNo={0}]", custNo);
It selects the Customers elements instead, but since you're just checking for existence, that's unimportant.
W3Schools has a good tutorial/reference on XPath.
I am using an xml file from this link..
http://www.goalserve.com/samples/soccer_livescore.xml
..
Lets say "category" is our "Tournament" then
I need to search and show the ---
1. The listing of all the "Tournaments" in gridview or datalist.
2. The listing of matches within a selected "Tournament"..
3. The listing of events within the matches etc..
Pls guide me how to achieve this... M using a Dataset.Readxml but then the inner linking of fields become very complex...
Pls guide...
Thanks..n..regards,
The simplest way to do this is with LINQ to XML. Something like this:
var doc = XDocument.Load(url);
var tournaments = doc.Root
.Elements("category")
.Where(x => (string) x.Attribute("name") == "Tournament")
.Single(); // Is there only one matching catgeory?
var matches = tournaments
.Elements("match")
.Select(m => new
{
LocalTeam = (string) m.Element("localteam").Attribute("name"),
VisitorTeam = (string) m.Element("localteam").Attribute("name"),
Events = m.Elements("Events")
.Select(e => new
{
Player = (string) e.Attribute("player"),
Type = (string) e.Attribute("type"),
// etc
})
.ToList();
});
How you display that is then up to you. You may want to create your own "normal" types for Event, Match etc rather than using the anonymous types above.
LINQ to XML is by far the simplest way of working with XML that I've used.
Greetings. Im having a small trouble i would like to have some help with. Im having a very large xml file with about 1000 customers with diffrent customer information. And I would like to do methods to retrive this information. Ive been searching everywhere but cant seem to find what im looking for. Currently im trying:
public custInformation getcustInfo(string file) {
//Load the xml file
var xe = XDocument.Load(_server.MapPath(file)).Root;
//Get information
return (from p in xe.Descendants("cust-account").Descendants("cust-info")
select new custInformation
{
firstName = (string)p.Element("cust-fname"),
lastName = (string)p.Element("cust-lname"),
address = (string)p.Element("cust-address1"),
}).(All elements)??
}
(All elements) is where id like to retrive all the information. Using FirstOrDefault will only retrive the first element and LastOrDefault will only retrive the first element. If some one could help me i would be very greatefull.
you want a list of customers. Change the return value to IEnumerable
and transform the query to IEnumerable with ToList()/ToArray():
public IEnumerable<custInformation> getcustInfo(string file) {
//Load the xml file
var xe = XDocument.Load(_server.MapPath(file)).Root;
//Get information
return (from p in xe.Descendants("cust-account").Descendants("cust-info")
select new custInformation
{
firstName = (string)p.Element("cust-fname"),
lastName = (string)p.Element("cust-lname"),
address = (string)p.Element("cust-address1"),
}).ToList();
}