I am attempting to create a loop to read through each XML attribute in a node and put it into a datatable. I have created my datatable with columns that are the same name as the attributes in my XML. I keep getting an error which says "Unable to cast object of type 'System.Xml.XmlElement' to type 'System.Xml.XmlAttribute'." The code follows: - foreach (XmlNode listItem in newBatch)
-
{
-
if (listItem.NodeType == XmlNodeType.Element)
-
{
-
foreach (XmlNode subNode in listItem)
-
{
-
string XMLtoREAD = subNode.OuterXml;
-
XmlDocument AttribXML = new XmlDocument();
-
AttribXML.LoadXml(XMLtoREAD);
-
-
-
//Find datatable
-
DataTable Items = ROV;
-
DataRow dr;
-
dr = Items.NewRow();
-
-
//Open Xml to read attributes
-
XmlTextReader reader = new XmlTextReader(new StringReader(XMLtoREAD));
-
reader.WhitespaceHandling = System.Xml.WhitespaceHandling.None;
-
reader.Read();
-
foreach (XmlAttribute attrib in AttribXML)
-
{
-
-
string AttName = attrib.ToString();
-
reader.MoveToAttribute(AttName);
-
dr[AttName] = reader.Value;
-
MessageBox.Show(reader.Value);
-
-
}
-
-
Items.Rows.Add(dr);
-
Items.AcceptChanges();
-
reader.Close();
-
-
}
-
}
-
}
The XML I am trying to read is: - <rs:data ItemCount="1" xmlns:rs="urn:schemas-microsoft-com:rowset">
-
<z:row ows_Date="2010-05-12 00:00:00" ows_Title="9" ows_Serial_x0020_Number="258" ows_Invoice_x0020_Number="254" ows_Supplier="synnex" ows_SKU="25365" ows_Manufacturer="8" ows_Description="15" ows_Qty_x002e_="1" ows_Price="235" ows_Freight="100" ows_Customer="as" ows_Total_x0020_Price="45" ows_ID="58" ows__ModerationStatus="0" ows__Level="1" ows_owshiddenversion="1" ows_UniqueId="58;#{88D9AAB5-61A9-46F7-80A4-DDBCA8C39475}" ows_FSObjType="58;#0" ows_Created="2010-05-12 11:49:01" ows_FileRef="58;#Calls/Lists/Parts/58_.000" ows_MetaInfo="58;#" xmlns:z="#RowsetSchema" />
-
</rs:data>
-
If you can't tell already, this is from a SharePoint query. I am not a developer, but I'm having fun playing around with .NET and creating forms to make my SharePoint more accessible. I appreciate any help people can give, and I look forward to replies.
Moderator: Please move this to the C# Forum, I did not realize there was a better place to post. done. --insertAlias
Everytime insertAlias posts on an XML topic it makes me realize that darnit, I really need to get on that LINQ thing! So much eaiser :D
That said, the problem with your code here is that you're loading the xml code again into a new xml document on line 8 and 9. Then you process it as an XmlAttribute when it's actually an XmlDocument. I think your loop online 21 might need to be changed to... - foreach (XmlAttribute attrib in AttribXML.DocumentElement.Attributes)
(Note: This next section has nothing to do with anything, really... just digressing :D)
Now, if you're noob (or old school, whatever your perspective!!) like me and like using XML this way, recursion helps make things soooo much nicer :)
I wrote up a little example to help you out... it's for output to a console but you get the idea, I'm sure. - class Program
-
{
-
static void Main(string[] args)
-
{
-
string xmlRaw = "<rs:data ItemCount=\"1\" xmlns:rs=\"urn:schemas-microsoft-com:rowset\">" +
-
" <z:row ows_Date=\"2010-05-12 00:00:00\" ows_Title=\"9\" ows_Serial_x0020_Number=\"258\" ows_Invoice_x0020_Number=\"254\" ows_Supplier=\"synnex\" ows_SKU=\"25365\" ows_Manufacturer=\"8\" ows_Description=\"15\" ows_Qty_x002e_=\"1\" ows_Price=\"235\" ows_Freight=\"100\" ows_Customer=\"as\" ows_Total_x0020_Price=\"45\" ows_ID=\"58\" ows__ModerationStatus=\"0\" ows__Level=\"1\" ows_owshiddenversion=\"1\" ows_UniqueId=\"58;#{88D9AAB5-61A9-46F7-80A4-DDBCA8C39475}\" ows_FSObjType=\"58;#0\" ows_Created=\"2010-05-12 11:49:01\" ows_FileRef=\"58;#Calls/Lists/Parts/58_.000\" ows_MetaInfo=\"58;#\" xmlns:z=\"#RowsetSchema\" />" +
-
" <z:row attrib1=\"blah\" attrib2=\"stuff\" xmlns:z=\"#RowsetSchema\" />" +
-
" <extra>" +
-
" <blah attrib1=\"eh?\" attrib2=\"yep\" />" +
-
" </extra>" +
-
"</rs:data>";
-
-
XmlDocument xmlDoc = new XmlDocument();
-
xmlDoc.LoadXml(xmlRaw);
-
-
ProcessNode(0, xmlDoc.DocumentElement);
-
}
-
-
public static void ProcessNode(int indent, XmlNode node)
-
{
-
if (node != null)
-
{
-
if (node.NodeType == XmlNodeType.Element)
-
{
-
// Output name
-
Output(indent, "Node: " + node.Name);
-
string sep = "".PadLeft(6 + node.Name.Length, '=');
-
Output(indent, sep);
-
-
// Output attributes
-
if (node.Attributes != null && node.Attributes.Count > 0)
-
{
-
Output(indent, "Attributes:");
-
Output(indent, "-----------");
-
foreach (XmlAttribute attrib in node.Attributes)
-
{
-
Output(indent, "Name: " + attrib.Name);
-
Output(indent, "Value: " + attrib.Value);
-
Output(0, "");
-
}
-
}
-
-
// Output child nodes
-
if (node.ChildNodes != null && node.ChildNodes.Count > 0)
-
{
-
Output(indent, "Children:");
-
Output(indent, "---------");
-
foreach (XmlNode childNode in node.ChildNodes)
-
{
-
ProcessNode(indent + 2, childNode);
-
}
-
}
-
}
-
}
-
}
-
-
public static void Output(int indent, string text)
-
{
-
text = text.PadLeft(indent + text.Length, ' ');
-
Console.WriteLine(text);
-
}
-
}
24 19301
I honestly think you are doing this the hard way.
Can I ask what version of .NET you are using? If it is 3.0 or higher, you can use the System.Xml.Linq objects, which are much easier to work with. - XmlNode response = proxy.GetListItems("listName", null, query, viewFields, null, queryOptions, null); //this is where you get the xml back from the list web service, use your own values
-
XElement element = XElement.Parse(response.OuterXml);
-
XNamespace ns = "#RowsetSchema";
-
List<XElement> elementList = element.Descendants().Where(x => x.Name == ns + "row").ToList();
-
DataTable table = new DataTable();//use your own table here instead of this blank table I created.
-
foreach (XElement e in elementList)
-
{
-
DataRow row = table.NewRow();
-
foreach (XAttribute a in e.Attributes())
-
row[a.Name.LocalName] = a.Value;
-
table.Rows.Add(row);
-
}
-
Console.ReadKey();
Everytime insertAlias posts on an XML topic it makes me realize that darnit, I really need to get on that LINQ thing! So much eaiser :D
That said, the problem with your code here is that you're loading the xml code again into a new xml document on line 8 and 9. Then you process it as an XmlAttribute when it's actually an XmlDocument. I think your loop online 21 might need to be changed to... - foreach (XmlAttribute attrib in AttribXML.DocumentElement.Attributes)
(Note: This next section has nothing to do with anything, really... just digressing :D)
Now, if you're noob (or old school, whatever your perspective!!) like me and like using XML this way, recursion helps make things soooo much nicer :)
I wrote up a little example to help you out... it's for output to a console but you get the idea, I'm sure. - class Program
-
{
-
static void Main(string[] args)
-
{
-
string xmlRaw = "<rs:data ItemCount=\"1\" xmlns:rs=\"urn:schemas-microsoft-com:rowset\">" +
-
" <z:row ows_Date=\"2010-05-12 00:00:00\" ows_Title=\"9\" ows_Serial_x0020_Number=\"258\" ows_Invoice_x0020_Number=\"254\" ows_Supplier=\"synnex\" ows_SKU=\"25365\" ows_Manufacturer=\"8\" ows_Description=\"15\" ows_Qty_x002e_=\"1\" ows_Price=\"235\" ows_Freight=\"100\" ows_Customer=\"as\" ows_Total_x0020_Price=\"45\" ows_ID=\"58\" ows__ModerationStatus=\"0\" ows__Level=\"1\" ows_owshiddenversion=\"1\" ows_UniqueId=\"58;#{88D9AAB5-61A9-46F7-80A4-DDBCA8C39475}\" ows_FSObjType=\"58;#0\" ows_Created=\"2010-05-12 11:49:01\" ows_FileRef=\"58;#Calls/Lists/Parts/58_.000\" ows_MetaInfo=\"58;#\" xmlns:z=\"#RowsetSchema\" />" +
-
" <z:row attrib1=\"blah\" attrib2=\"stuff\" xmlns:z=\"#RowsetSchema\" />" +
-
" <extra>" +
-
" <blah attrib1=\"eh?\" attrib2=\"yep\" />" +
-
" </extra>" +
-
"</rs:data>";
-
-
XmlDocument xmlDoc = new XmlDocument();
-
xmlDoc.LoadXml(xmlRaw);
-
-
ProcessNode(0, xmlDoc.DocumentElement);
-
}
-
-
public static void ProcessNode(int indent, XmlNode node)
-
{
-
if (node != null)
-
{
-
if (node.NodeType == XmlNodeType.Element)
-
{
-
// Output name
-
Output(indent, "Node: " + node.Name);
-
string sep = "".PadLeft(6 + node.Name.Length, '=');
-
Output(indent, sep);
-
-
// Output attributes
-
if (node.Attributes != null && node.Attributes.Count > 0)
-
{
-
Output(indent, "Attributes:");
-
Output(indent, "-----------");
-
foreach (XmlAttribute attrib in node.Attributes)
-
{
-
Output(indent, "Name: " + attrib.Name);
-
Output(indent, "Value: " + attrib.Value);
-
Output(0, "");
-
}
-
}
-
-
// Output child nodes
-
if (node.ChildNodes != null && node.ChildNodes.Count > 0)
-
{
-
Output(indent, "Children:");
-
Output(indent, "---------");
-
foreach (XmlNode childNode in node.ChildNodes)
-
{
-
ProcessNode(indent + 2, childNode);
-
}
-
}
-
}
-
}
-
}
-
-
public static void Output(int indent, string text)
-
{
-
text = text.PadLeft(indent + text.Length, ' ');
-
Console.WriteLine(text);
-
}
-
}
Haha, you simply must get onboard the LINQ train. Seriously, it will make your coding life so much easier. And not only for XML, but for SQL as well, and just objects in memory.
:D
Next project that I get with this stuff I'll probably dive in. The real problem though is that we're stuck using VS 2005 and .NET 2.0 at work (*** sigh ***) so I typically have to go back to the System.Xml stuff anyway.
I played around with your example a bit though. For the most part it's not terribly different other than that you can easily filter your query instead of bulk checking the whole node.
@insertAlias:
I am using 3.0, although I also use a Web Reference (which I understand to be 2.0?) are there any issues with mixing the two?
I guess the reason I haven't been using the LINQ is because the standard XML syntaxes made a little more sense. But now, seeing your example, I'll start trying to play with LINQ. I am also creating a phone app for WinPhone 7, which doesn't even have 2.0 available so I'm going to have to learn it some time anyway.
@GaryTexmo
Thanks for the reply. That actually is what I ended up doing. I changed line 21 to read: -
foreach (XmlAttribute attrib in AttribXML.DocumentElement.Attributes)
-
Which solved the problem.
Thanks guys!
It's also worth noting that you don't even need to declare that AttributeXML variable that way. You've got access to the attributes already via subNode.Attributes.
Actually it might be listItem.Attributes... you'll have to check your code. I don't think I had the full XML and context for what you're working on, so when I used your code I had the row nodes in my first foreach loop.
@PrezWeezy
Actually, I used a Web Reference (2.0) in that example there. We had some issues using service references for some reason.
Anyway, no, there's no problem mixing the two. Actually, you can get on the .NET 4.0 train now! Here's a link to the Visual Studio Express versions.
@GaryTexmo:
I actually have seperated out my listItem function because I am creating a query form, so depending on the type of query you make, it passes through different arguments. So I created a function for diong the parsing, which is what the code I posted is.
What do you mean about declaring AttributeXML? I ask because when I used the subnode.Attributes it gave me an error about implicitly converting something. I don't remember now.
@insertAlias:
Is there a way to use a service reference instead of a web reference? Since the Phone platform doesn't support web references I'm going to have to figure out a way to make it work somehow and I was wondering if there is a blanket way to make it work, specifically with sharepoint.
Umm...it's been a while since I've tried. I'm not sure off the top of my head. Let me look into it and get back to you.
I have one more quick question in regards to crossing classes, should I create a new thread or can you help me here?
<ProfessorFarnsworth> Good news, everyone!</ProfessorFarnsworth>
Figured it out, with the help of this site.
Here's what you do. Create your Service Reference using the same address as you did for the Web Reference.
Go into your app.config (or Web.config) and change this: - <security mode="None">
-
<transport clientCredentialType="None" proxyCredentialType="None"
-
realm="" />
-
<message clientCredentialType="UserName" algorithmSuite="Default" />
-
</security>
to this: - <security mode="TransportCredentialOnly">
-
<transport clientCredentialType="Ntlm" proxyCredentialType="None"
-
realm="" />
-
<message clientCredentialType="UserName" algorithmSuite="Default" />
-
</security>
Then in your code file: -
//this is whatever your soap client is named
-
Lists.ListsSoapClient proxy = new Lists.ListsSoapClient();
- proxy.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
That should do it.
Here's the code I used to get a list of all the XML Elements in a Sharepoint List: - Lists.ListsSoapClient proxy = new Lists.ListsSoapClient();
-
proxy.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
-
XElement query = new XElement("Query");
-
XElement queryOptions = new XElement("QueryOptions");
-
XElement viewFields = new XElement("ViewFields");
-
XElement response = proxy.GetListItems("Cafe", null, query, viewFields, null, queryOptions, null);
-
XNamespace ns = "#RowsetSchema";
-
List<XElement> elementList = response.Descendants().Where(x => x.Name == ns + "row").ToList();
-
Console.ReadKey();
Just post your new question in this thread. If I feel like it needs its own thread, I'll split it for you.
Ok, so the form I'm creating has the first form which queries the SharePoint list, then sends the info to a DataGridView. I want to then be able to double click on one of the items in the DataGridView, and have it open that item in another form. I'm having trouble finding out how to make my datatable accessible to other classes. I've tried just making it public static, public void, everything I know how. I would like to actually have a "Tables.cs" which holds all of the definitions for my tables and then all of the forms simply access the tables from those different classes. When I do that and then try to bind my datagridview to that table from another class it comes up blank. Is there a trick?
@PrezWeezy
Well, it looks like you're doing this..
* Get node
* Get child node
* Get XML string for child code
* Load XML string into new XML document
* Parse new XML document for attributes
... when all you really need to do is ...
* Get node
* Get child node
* Get attributes for child node
I don't get why you're converting the XmlNode into a string (xml string), loading it back into another xml document, then getting that XmlNode and reading the attributes. Skip the middle man?
Am I missing something?
@PrezWeezy
Well, its a bad idea to use your table like that. Instead, you should be using it's underlying data source.
What I would do is get the row's item, then pass that item to the second form as a parameter.
May I ask why you don't want to do that? I would kind of like to be able to have a "next" and "previous" button on the edit form, then dump the table back into a batch to update the sharepoint list items. What's the reason for not using the tables as my storage to move back and forth through the rows?
In the end, I want everything to run in memory only. My reasoning is simply that then I don't need to worry about permissions to write files and I don't have to worry about trying to run as administrator to write to the program files location. Is there a better way to accomplish this?
Ok, when I said table, I should have said "DataGridView." You don't want to be passing around your UI object, because it's a lot of overhead, and completely unnecessary.
What you can do is use the UI object's underlying datasource. You can actually expose that as a public property of your form, and pass the index of the value you are working with to the second form. That way, the second form can get the proper value from the first form's property, and can still go back and forth.
If you're doing things right, the updates you make in your DataGridView are reflected to it's DataSource, and vice versa.
Basically, you should separate your data from presentation. The datasource is still in memory, you just wouldn't be passing all the extraneous information about the datagridview that you don't care about.
Yes, that's exactly what I want to do. I just can't seem to make my DataTable accessible from the other classes. I really want to have a class dedicated to holding my tables (I have several) and then just call those tables from my different forms. I just can't seem to get the right "public" return type to make it work.
Ok, if you want to do that, you would create the class, with public parameters of each DataTable you will want.
Then in your first form, you will have a public property that is an instance of that class, and you will initialize it in the constructor.
Then your second form can access it from the first form.
Something like:
Class file -
public class Tables
-
{
-
public DataTable MyTable {get;set;}
-
public DataTable MySecondTable {get;set;}
-
}
Form1 -
public class Form1
-
{
-
public Tables MyTables {get;set;}
-
-
public Form1()
-
{
-
MyTables = new Tables();
-
//set the data table to the object
-
MyTables.MyTable = someDataTable;
-
}
-
}
In Form2 you will need a reference to the instantiated Form1.
I've been playing with this for a few days now, and I still can't get it to work. Here's what I have for my code in my tables class: -
public class Tables
-
{
-
DataTable ROV = new DataTable();
-
public DataTable ReturnedOrderValues
-
{
-
set {
-
DataColumn Title = new DataColumn();
-
Title.ColumnName = "ows_Title";
-
Title.Caption = "Order Number";
-
ROV.Columns.Add(Title);
-
-
}
-
get { return ROV; }
-
-
}
-
Then I call that from my form class with: -
DataTable Items = new DataTable();
-
Items = MyTables.ReturnedOrderValues;
-
DataRow dr;
-
dr = Items.NewRow();
-
And my binding source (which I know works when I make the table within the same class: -
BindingSource ItemsSource = new BindingSource();
-
ItemsSource.DataSource = MyTables.ReturnedOrderValues;
-
OrderDataGrid.DataSource = ItemsSource;
-
What do I have wrong here? Thanks again for all of the help!
I'm honestly not sure. I'm leaving this reply to remind myself to look at it a bit closer tomorrow.
So were you able to see what I've done wrong? I keep messing with it and I'm not really getting anywhere.
I'm sorry, I'm at a bit of a loss, I'll ask the experts to come take a look.
Sign in to post your reply or Sign up for a free account.
Similar topics
by: Sturnoff Megantic |
last post by:
This seems like such a stupid little problem, but it's been bugging me
for hours now. I have a 2D array called agents2d. I need to loop
through it and display the info. Here is my code:
echo...
|
by: Anita C |
last post by:
I have the foll. code to update the value of an attribute:
xmlDocument.Load("abc.xml");
XmlAttribute xmlAttrib = xmlDocument.SelectSingleNode(root/web/theme/@desc);
xmlAttrib.Value =...
|
by: cody |
last post by:
What about an enhancement of foreach loops which allows a syntax like that:
foeach(int i in 1..10) { } // forward
foeach(int i in 99..2) { } // backwards
foeach(char c in 'a'..'z') { } // chars...
|
by: David C |
last post by:
This is very strange. Say I have code like this. I am simply looping
through a collection object in a foreach loop.
Course course = new Course();
foreach(Student s in course.Students)
{...
|
by: John Dalberg |
last post by:
In a traditional for loop, one can use the index (say i) and continue
looping in another function and come back to original for loop (even though
it's not good practice)
Can the newer foreach...
|
by: Sjoerd |
last post by:
Summary: Use foreach(..) instead of while(list(..)=each(..)).
--==--
Foreach is a language construct, meant for looping through arrays.
There are two syntaxes; the second is a minor but useful...
|
by: Benjamin |
last post by:
I am attempting to create multiple itterators for a custom class that I have created. Basically I have a class that I am populating using XML de-serialization. I want to be able to loop through the...
|
by: assgar |
last post by:
Hi
I am having problem with my loping.
I don't know if I have chosen the correct approach.
GOAL:
I need to insert into a table event types for a specific date range.
The calendar the event...
|
by: lashaw |
last post by:
This program is suppose to only display one name and number after the buttom is pressed. But the problem is it only displays the first name and number after the button is pressed. It won't display...
|
by: CloudSolutions |
last post by:
Introduction:
For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
|
by: Faith0G |
last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome former...
|
by: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: ryjfgjl |
last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
| |