I have XML file like below
<?xml version="1.0" standalone="yes"?>
<ShippersDataSet xmlns="http://www.tempuri.org/ShippersDataSet.xsd">
<Shippers>
<ShipperID>1</ShipperID>
<CompanyName>Speedy Express</CompanyName>
<Phone>(503) 555-9831</Phone>
</Shippers>
<Shippers>
<ShipperID>2</ShipperID>
<CompanyName>United Package</CompanyName>
<Phone>(503) 555-3199</Phone>
</Shippers>
<Shippers>
<ShipperID>3</ShipperID>
<CompanyName>Federal Shipping</CompanyName>
<Phone>(503) 555-9931</Phone>
</Shippers>
</ShippersDataSet>
I have following input for XML data :
string XMLpath, string query
Query :
<Query>
<ElementPath> Shippers</ElementPath>
</Query>
I need to add
Like following , ( I have achieved in SQL) same way I need to add for XML data
var list = new List<Myclassdef>();
using (var con = new SqlConnection(Settings.Default.ConnectionString))
{
using (var cmd = new SqlCommand("SELECT ... WHERE Col1=#param1", con))
{
cmd.Parameters.AddWithValue("#param1", "value1");
// ...
con.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Myclassdef data = new Myclassdef();
data.Data = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
{
data.Data.Add(reader.GetName(i), reader[i]);
}
list.Add(data);
}
}
}
}
I have following input for XML data :
string XMLpath, string query
Query :
<Query><ElementPath> Shippers</ElementPath></Query>
Try this:
class Program
{
static void Main(string[] args)
{
var list = new List<Myclassdef>();
var query = XDocument
.Parse("<Query><ElementPath> Shippers</ElementPath></Query>");
var doc = XDocument.Parse(File.ReadAllText("xml.xml"));
doc.Descendants(
XName.Get(
query.Root.Value.Trim(),
doc.Root.GetDefaultNamespace().NamespaceName))
.ToList()
.ForEach(e =>
{
var data = new Myclassdef();
data.Data = e
.Elements()
.Select(c => new
{
Name = c.Name.LocalName,
Value = (object)c.Value
})
.ToDictionary(c => c.Name, c => c.Value);
list.Add(data);
});
}
}
You can use Linq to XML for that (namespace System.Xml.Linq):
XDocument document = XDocument.Load(stream); // load the xml into an XDocument from a stream
// select the first of a specific element
IEnumerable<XElement> elements = from shippers in document.Descendants("Shippers") select shippers;
XElement element = (XElement)elements.First().FirstNode;
// loop through all the elements inside that element
foreach (XNode node in elements.First().Nodes())
{
// do something with elements
}
Related
I have a problem with this XML. In our system we are using XML from DataSet (ds.GetXml()) and send it to our Silverlight application as a string. From there we read the XML with the following:
StringReader stream = new StringReader(XmlData);
XmlReader reader = XmlReader.Create(stream);
XDocument myDoc = new XDocument();
myDoc = XDocument.Load(reader);
The problem: Some times column names are changed, example: If a column name starts with a numeric number then it will convert it.
"_x0033_column" original column name was "3column"
Is it possible to get the original column name from the XML?
The XML
<NewDataSet>
<Table>
<CheckboxCol>0</CheckboxCol>
<Kunde>1</Kunde>
<Ort_x0020_Postfach />
<erfasst_x0020_von>MasterMind</erfasst_x0020_von>
<Buchhaltungsnummer>1</Buchhaltungsnummer>
<Kreditlimit>0.0000</Kreditlimit>
<_x0033_STT_Inaktiv>Nein</_x0033_STT_Inaktiv>
<_x0033_STT_Status>Interessent</_x0033_STT_Status>
<Zahlungsbedingungen>10 : 10 Tage Netto</Zahlungsbedingungen>
</Table>
<Table>
<CheckboxCol>0</CheckboxCol>
<Kunde>3</Kunde>
<Ort_x0020_Postfach />
<erfasst_x0020_von>MasterMind</erfasst_x0020_von>
<Buchhaltungsnummer>3</Buchhaltungsnummer>
<Kreditlimit>0.0000</Kreditlimit>
<_x0033_STT_Inaktiv>Nein</_x0033_STT_Inaktiv>
<_x0033_STT_Status>Kunde</_x0033_STT_Status>
<Zahlungsbedingungen>10 : 10 Tage Netto</Zahlungsbedingungen>
</Table>
<NewDataSet>
My current Code
public SLDataTable(string XmlData, Dictionary<string, string> ColumnDict)
{
ColumnDefination = ColumnDict;
foreach (var Item in ColumnDefination)
{
Columns.Add(new SLDataColumn() { ColumnName = Item.Key.ToString().Trim(), DataType = GetNullableType(GetColumnType(Item.Value.ToString())) });
}
StringReader stream = new StringReader(XmlData);
XmlReader reader = XmlReader.Create(stream);
XDocument myDoc = new XDocument();
myDoc = XDocument.Parse(XmlData);
if (myDoc != null && myDoc.Elements().Count() > 0 && myDoc.Element("NewDataSet").Elements().Count() > 0)
{
int columnCount = myDoc.Element("NewDataSet").Element("Table").Elements().Count();
int rowCount = myDoc.Element("NewDataSet").Elements().Count();
string ElmentColumnName = string.Empty;
foreach (XElement element in myDoc.Element("NewDataSet").Elements())
{
var row = new SLDataRow(this);
foreach (XElement ele in element.Elements())
{
ElmentColumnName = ele.Name.ToString().Replace("_x0020_", " ").Replace("_x0028_", " (").Replace("_x0029_", ") ");
row[ElmentColumnName] = ConvertValue(ElmentColumnName, ele.Value);
}
Rows.Add(row);
}
}
}
I want the function below to read an XML file and save all the data into the UserClassDict that is passed into the function. The UserClassDict saves the a (username,User Class). The User Class has a property List<int> ControlNumber , where it stores the ControlNumbers.
The XML that it is trying to read looks like this :
<UserClassDictionary>
<adolan>
<ControlNumber>791301</ControlNumber>
</adolan>
<afeazell>
<ControlNumber>790253</ControlNumber>
</afeazell>
<asnyder>
<ControlNumber>790210</ControlNumber>
<ControlNumber>790308</ControlNumber>
</asnyder>
<semery/>
<showard/>
<talexander/>
</UserClassDictionary>
The problem that I'm having is that the LINQ in the function doesn't seem distinguish between the different xml nodes. It doesn't seem to set the node to the Key and the node to the Value.
static void XMLToDictionary(Dictionary<string,User> UserClassDict)
{
XmlDocument doc = new XmlDocument();
doc.Load("UserClassDictionary.xml");
StringWriter sw = new StringWriter();
XmlTextWriter tx = new XmlTextWriter(sw);
doc.WriteTo(tx);
string str = sw.ToString();
XDocument document = XDocument.Parse(str);
foreach (XElement element in document.Descendants().Where(p => p.HasElements == false))
{
int keyInt = 0;
string keyName = element.Name.LocalName;
while (UserClassDict.ContainsKey(keyName))
keyName = element.Name.LocalName + "_" + keyInt++;
UserClassDict.Add(keyName, element.Value);
}
}
First, you don't need a StreamWriter or XmlTextWriter. You can just use XElement.Load() instead.
XElement root = XElement.Load("UserClassDictionary.xml");
Dictionary<string, List<string>> values = new Dictionary<string, List<string>>();
foreach(XElement subNode in root.Elements().Where(x => x.Elements().Count() > 0))
{
values.Add(subNode.Name.LocalName, subNode.Elements("ControlNumber")
.Select(x => x.Value).ToList());
}
Your other reason was you were using Descendents instead of Elements in your loop. This looked for EVERY sub node in your xml, even gradchild nodes.
You can parse your xml and create dictionary of users with Linq to XML:
XDocument xdoc = XDocument.Load("UserClassDictionary.xml");
Dictionary<string, User> users =
xdoc.Root.Elements()
.Select(u => new User {
Name = u.Name.LocalName,
ControlNumber = u.Elements().Select(cn => (int)cn).ToList()
})
.Where(u => ControlNumber.Any())
.ToDictionary(u => u.Name);
Or if you wish to update existing dictionary
var users = from u in xdoc.Root.Elements()
where u.Elements().Any()
select new User {
Name = u.Name.LocalName,
ControlNumber = u.Elements().Select(cn => (int)cn).ToList()
};
foreach(var user in users)
UserClassDict.Add(user.Name, user);
How would I go about getting the ID information using Linq. I'm trying to add them to an array of int.
<FactionAttributes>
<name>Player</name>
<id>0</id>
<relationModifier>1</relationModifier>
<relations>
<id0>100</id0>
<id1>50</id1>
<id2>50</id2>
<id3>50</id3>
<id4>50</id4>
<id5>50</id5>
</relations>
</FactionAttributes>
That is my XML.
Here is the code I'm using so far.
void InitFactions()
{
int count = 0;
string filepath = Application.dataPath + "/Resources/factiondata.xml";
XDocument factionXML = XDocument.Load(filepath);
var factionNames = from factionName in factionXML.Root.Elements("FactionAttributes")
select new {
factionName_XML = (string)factionName.Element("name"),
factionID_XML = (int)factionName.Element("id"),
factionRelations_XML = factionName.Element("relations")// Need to turn this into array.
};
foreach ( var factionName in factionNames)
++count;
foreach ( var factionName in factionNames)
{
Factions f = new Factions();
f.otherFactionsName = new string[count];
f.otherFactionsRelation = new int[count];
int others = 0;
f.FactionName = factionName.factionName_XML;
Debug.Log(factionName.factionRelations_XML);
// Adds Rivals, not self to other list.
foreach (var factionName2 in factionNames)
{
if (factionName.factionID_XML == factionName2.factionID_XML)
continue;
f.otherFactionsName[(int)factionName2.factionID_XML] = factionName2.factionName_XML;
// THIS IS WHERE IM ADDING THE RELATIONS IN //
f.otherFactionsRelation[(int)factionName2.factionID_XML] = factionName.factionRelations_XML[(int)factionName2.factionID_XML];
Debug.Log(f.FactionName + " adds: " + factionName2.factionName_XML);
++others;
}
}
}
I have made multiple attempts using nodes and what not. I can't seem to figure out the correct syntax.
XDocument doc = XDocument.Load(Path);
//To get <id>
var MyIds = doc.Element("FactionAttributes").Element("id").Value;
//To get <id0>, <id1>, etc.
var result = doc.Element("FactionAttributes")
.Element("relations")
.Elements()
.Where(E => E.Name.ToString().Contains("id"))
.Select(E => new { IdName = E.Name, Value = E.Value});
If you want array of ints replace the select with this
.Select(E => Convert.ToInt32(E.Value)).ToArray();
If you are just after the relations Ids use this simple query
var doc = XDocument.Load("c:\\tmp\\test.xml");
var ids = doc.Descendants("relations").Elements().Select(x => x.Value);
If you want the Id and the relations ids in one array use this
var id = doc.Descendants("id").Select(x=>x.Value).Concat(doc.Descendants("relations").Elements().Select(x => x.Value));
I'm having an xml file like
<Root>
<Child val1="1" val2="2"/>
<Child val1="1" val2="3"/>
<Child val1="2" val2="4"/>
</Root>
i need to display the data from the Xml file to a Listview like
(Added A to index value)
Now i'm using like
1.Stores the data in an XmlNodesList
2.Then iterate through the nodeslist and add the attribute value to the list view
Here i can not use Dictionary<String,String> as a temporary storage because there exist multiple keys with same name.
Is there any idea to do this using LINQ to XML.?
Without LINQ:
var doc = new System.Xml.XmlDocument();
doc.LoadXml(xml);
var nodes = doc.SelectNodes("Root/Child");
for (int i = 0; i < nodes.Count; i++)
{
var n = nodes[i];
var index = String.Format("A{0}", i + 1);
var column1 = n.Attributes["val1"].Value;
var column2 = n.Attributes["val1"].Value;
// use variables to add an item to ListView
}
Using LINQ:
using System.Linq;
var doc = new System.Xml.XmlDocument();
doc.LoadXml(xml);
var nodes = doc.SelectNodes("Root/Child");
var arr = nodes
.OfType<XmlNode>()
.ToArray();
var result = arr
.Select(n =>
new
{
ClNo = String.Format("A{0}", Array.IndexOf(arr, n) +1),
Val1 = n.Attributes["val1"].Value,
Val2 = n.Attributes["val2"].Value,
});
ListView list = new ListView();
ListViewItem[] items = result
.Select(r => new ListViewItem(new[] { r.ClNo, r.Val1, r.Val2 })
.ToArray();
list.Items.AddRange(items);
what is the best way of reading xml file using linq and the below code you will see that, I have three different loops and I feel like its not elegant or do I have options to retrofit the below code?
public static void readXMLOutput(Stream stream)
{
XDocument xml = new XDocument();
xml = LoadFromStream(stream);
var header = from p in xml.Elements("App").Elements("Application")
select p;
foreach (var record in header)
{
string noym = record.Element("nomy").Value;
string Description = record.Element("Description").Value;
string Name = record.Element("Name").Value;
string Code = record.Element("Code").Value;
}
var appRoles = from q in xml.Elements("App").Elements("Application").Elements("AppRoles").Elements("Role")
select q;
foreach (var record1 in appRoles)
{
string Name = record1.Element("Name").Value;
string modifiedName = record1.Element("ModifiedName").Value;
}
var memeber = from r in xml.Elements("App").Elements("Application").Elements("AppRoles").Elements("Role").Elements("Members")
select r;
foreach (var record2 in memeber)
{
string ExpirationDate = record2.Element("ExpirationDate").Value;
string FullName = record2.Element("FullName").Value;
}
}
UPDATED:
foreach (var record in headers)
{
..............
string Name1 = record.Attribute("Name").Value;
string UnmodifiedName = record.Attribute("UnmodifiedName").Value;
string ExpirationDate = record.Attribute("ExpirationDate").Value;
string FullName = record.Attribute("FullName").Value;
...............
}
Is that your actual code ? All those string variables you are assigning in the foreach loops only have a scope of one iteration of the loop. They are created and destroyed each time.
This may not work precisely in your case depending on the xml structure. Play around with it. Try it using LinqPad
var applications = from p in xml.Descendants("Application")
select new { Nomy = p.Element("nomy").Value
, Description = p.Element("Description").Value
, Name = p.Element("Name").Value
, Code = p.Element("Code").Value
};
var appRoles = from r in xml.Descendants("Role")
select new { Name = r.Element("Name").Value
, ModifiedName = r.Element("ModifiedName").Value
};
This answer is a hierarchical query.
var headers =
from header in xml.Elements("App").Elements("Application")
select new XElement("Header",
new XAttribute("noym", header.Element("nomy").Value),
new XAttribute("Description", header.Element("Description").Value),
new XAttribute("Name", header.Element("Name").Value),
new XAttribute("Code", header.Element("Code").Value),
from role in header.Elements("AppRoles").Elements("Role")
select new XElement("Role",
new XAttribute("Name", role.Element("Name").Value),
new XAttribute("ModifiedName", role.Element("ModifiedName").Value),
from member in role.Elements("Members")
select new XElement("Member",
new XAttribute("ExpirationDate", member.Element("ExpirationDate").Value),
new XAttribute("FullName", member.Element("FullName").Value)
)
)
);