I want to parse an XML file like this:
<?xml version="1.0" encoding="utf-8" ?>
<database name="myDb">
<table name="myTable">
<field name="Code" type="int" size="0" identity="true" primarykey="true" description="کد شناسه" reference=""></field>
<field name="Name" type="nvarchar" size="50" identity="false" primarykey="false" description="نام شخص" reference=""></field>
</table>
<table name="yourTable">
<field name="Code" type="int" size="0" identity="true" primarykey="true" description="کد شناسه" reference=""></field>
<field name="Title" type="nvarchar" size="50" identity="false" primarykey="false" description="نام شخص" reference=""></field>
</table>
</database>
The problem is that in my inner foreach it will parse 4 fields instead of 2 fields related to each table. how to change the code to read only the fields for current table?
XDocument xdoc = XDocument.Load("d:\\tables.xml");
foreach (XNode table in xdoc.Descendants("database").Nodes())
{
fields = "";
tableName = XElement.Parse(table.ToString()).Attribute("name").Value;
//XElement xE = XElement.Parse(table.ToString());
//foreach (XElement e in xE.Elements())
foreach (XNode field in xdoc.Descendants("table").Nodes())
{
fieldName = XElement.Parse(field.ToString()).Attribute("name").Value;
type = XElement.Parse(field.ToString()).Attribute("type").Value;
size = XElement.Parse(field.ToString()).Attribute("size").Value;
identity = XElement.Parse(field.ToString()).Attribute("identity").Value;
primarykey = XElement.Parse(field.ToString()).Attribute("primarykey").Value;
description = XElement.Parse(field.ToString()).Attribute("description").Value;
reference = XElement.Parse(field.ToString()).Attribute("reference").Value;
if (identity == "true") identity = "identity";
if (primarykey == "true") primarykey = "primary key";
if (isChar(type))
{
fields += string.Format(fieldCharTemplate, fieldName, type, size);
}
else
{
fields += string.Format(fieldNonCharTemplate, fieldName, type, identity,primarykey);
}
//var y = x.Element("type");
}
sql = string.Format(tableTemplate, tableName, fields);
Response.Write(sql);
}
This is the problem:
foreach (XNode field in xdoc.Descendants("table").Nodes())
That's looking for all nodes under all table
elements. You don't want that.
You've already got the table you're looking at as an XElement
- so use that. It requires that your table
variable is an XElement
rather than just XNode
, but that's what you really want anyway... and it means you don't have to reparse it to get the table name. I would write your code as:
foreach (XElement table in xdoc.Root.Elements("table"))
{
string tableName = (string) table.Attribute("name");
StringBuilder fields = new StringBuilder();
foreach (XElement field in table.Elements("field"))
{
string fieldName = (string) field.Attribute("name");
string type = (string) field.Attribute("type");
// Consider casting to int instead...
string size = (string) field.Attribute("size");
bool identity = (bool) field.Attribute("identity");
bool primaryKey = (bool) field.Attribute("primarykey");
string description = (string) field.Attribute("description");
string reference = (string) field.Attribute("reference");
// Append to fields here
}
}
Note how much simpler it is to get to the attributes when you already have an element. You really shouldn't need to do multiple parse operations in the vast majority of cases. Also note how I've used the conversion to bool
for primarykey
and identity
. Again, this is cleaner than testing the string manually.
See more on this question at Stackoverflow