After performing some tests, it seems that DataSet.ReadXml
is not able to correctly infer the data schema if there is a field whose name matches the name of the superior element. It is probably something inherent to the internal implementation of the method and the way of traversing the nodes to infer the schema of the data.
Having seen this, you have two options:
Rename the table so that it does not match the one in the column:
...
<NumCodigos>
<NumCodigo>123456</NumCodigo>
</NumCodigos>
Include the schema of the data in your xml file. I'll put you as you would in your example:
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Productos">
<xs:complexType>
<xs:sequence>
<xs:element name="P11" type="xs:int" minOccurs="0" />
<xs:element name="P12" type="xs:int" minOccurs="0" />
<xs:element name="P14" type="xs:int" minOccurs="0" />
<xs:element name="P21" type="xs:int" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Cantidades">
<xs:complexType>
<xs:sequence>
<xs:element name="Tipo" type="xs:string" minOccurs="0" />
<xs:element name="Producto" type="xs:string" minOccurs="0" />
<xs:element name="NumCodigo" type="xs:int" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="NumCodigo">
<xs:complexType>
<xs:sequence>
<xs:element name="NumCodigo" type="xs:int" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<Productos>
<P11>1</P11>
<P12>1</P12>
<P14>1</P14>
<P21>0</P21>
</Productos>
<Cantidades>
<Tipo>A</Tipo>
<Producto>P11</Producto>
<NumCodigo>123456</NumCodigo>
</Cantidades>
<Cantidades>
<Tipo>B</Tipo>
<Producto>P12</Producto>
<NumCodigo>123456</NumCodigo>
</Cantidades>
<Cantidades>
<Tipo>C</Tipo>
<Producto>P14</Producto>
<NumCodigo>123456</NumCodigo>
</Cantidades>
<NumCodigo>
<NumCodigo>123456</NumCodigo>
</NumCodigo>
</NewDataSet>
If the xml file with the data is being generated by using DataSet.WriteXml
, what you should do is add the XmlWriteMode.WriteSchema
parameter to add the schema to the file:
ds.WriteXml(Server.MapPath("~/datos.xml"),XmlWriteMode.WriteSchema);
Edited
There is a third option, which you can use if (as it seems to be your case) you do not have access to modify the xml file. This option is to generate the data schema in your DataSet
before importing it. I'm going to use the example you've put:
//Creamos las tablas y campos necesarios:
DataTable dt1 = new DataTable("Productos");
dt1.Columns.Add("P11", typeof(int));
dt1.Columns.Add("P12", typeof(int));
dt1.Columns.Add("P14", typeof(int));
dt1.Columns.Add("P21", typeof(int));
DataTable dt2 = new DataTable("Cantidades");
dt2.Columns.Add("Tipo");
dt2.Columns.Add("Producto");
dt2.Columns.Add("NumCodigo", typeof(int));
DataTable dt3 = new DataTable("NumCodigo");
dt3.Columns.Add("NumCodigo");
//Añadimos las tablas a un nuevo DataSet
DataSet ds = new DataSet();
ds.Tables.Add(dt1);
ds.Tables.Add(dt2);
ds.Tables.Add(dt3);
//Ahora en ds ya tenemos el esquema de datos correcto. Ya podemos importar los datos
ds.ReadXml(Server.MapPath("~/datos.xml"));
var col = ds.Tables["NumCodigo"].Rows[0]["NumCodigo"];
Using this method, you must bear in mind that the tables and fields that you generate must match the xml data schema, and if this varies, you must modify it in your code as well.
Issue 2
I think the optimal way to solve the problem in your case is to have the schema in an xsd file, and read it before importing the data. Summing up:
-
You create a datos.xsd
file with the schema:
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Productos">
<xs:complexType>
<xs:sequence>
<xs:element name="P11" type="xs:int" minOccurs="0" />
<xs:element name="P12" type="xs:int" minOccurs="0" />
<xs:element name="P14" type="xs:int" minOccurs="0" />
<xs:element name="P21" type="xs:int" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Cantidades">
<xs:complexType>
<xs:sequence>
<xs:element name="Tipo" type="xs:string" minOccurs="0" />
<xs:element name="Producto" type="xs:string" minOccurs="0"/>
<xs:element name="NumCodigo" type="xs:int" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="NumCodigo">
<xs:complexType>
<xs:sequence>
<xs:element name="NumCodigo" type="xs:int" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
-
Now, we use the ReadXmlSchema
method to first read the schema and then import the data:
DataSet ds = new DataSet();
//leemos el esquema
ds.ReadXmlSchema(Server.MapPath("~/datos.xsd"));
//importamos los datos
ds.ReadXml(Server.MapPath("~/datos.xml"));
//accedemos a la columna
var col = ds1.Tables["NumCodigo"].Rows[0]["NumCodigo"];