2009-05-21 18 views
5

Estoy tratando de obtener un archivo XML en un conjunto de datos y estoy usando el siguiente código:Importar XML en conjunto de datos C#

DataSet ds = new DataSet("TestDataSet"); 
ds.ReadXml(FileName); 

y este archivo xml:

<Catalog> 
<Rec> 
    <ITEM dt:dt="string"/> 
    <QTY dt:dt="string">1</QTY> 
    <SUB dt:dt="string">1</SUB> 
    <CATALOG dt:dt="string">ABC123</CATALOG> 
    </Rec> 
    <Rec> 
    <ITEM dt:dt="string"/> 
    <QTY dt:dt="string">1</QTY> 
    <SUB dt:dt="string">1</SUB> 
    <CATALOG dt:dt="string">ABC124</CATALOG> 
    </Rec> 
    <Rec> 
    <ITEM dt:dt="string"/> 
    <QTY dt:dt="string">1</QTY> 
    <SUB dt:dt="string">1</SUB> 
    <CATALOG dt:dt="string">ABC125</CATALOG> 
    </Rec> 
</Catalog> 

El problema es que la después de configurar un reloj en ds, solo parece contener una tabla llamada Rec y una columna llamada Rec_Id. Si elimino el tipo de datos "dt: dt =" String "" todo funciona bien.

estoy usando C# .NET 2008 ...

Puede alguien por favor avise de la forma correcta para importar estos datos sin tener que modificar el archivo XML?

Gracias

+0

cómo se define el espacio de nombres dt? – Baget

+0

He hecho una pregunta similar y recibí una buena respuesta que me ayudó. Puedes echar un vistazo a mi [SO] (http://stackoverflow.com/questions/772946/import-xml-to-sql-using-c) – adopilot

Respuesta

1

Para que el ReadXml funcione correctamente en este caso, creo que es necesario especificar un esquema en el archivo XML. De lo contrario, el lector no sabrá qué hacer con los tipos de datos.

+0

Bingo. Como referencia, intente hacer un WriteXML en un DataSet conocido y vea lo que produce. Notarás en el nodo raíz para el nombre de clase que agrega los atributos de espacio de nombres mencionados por Jon. –

5

Tan pronto como defina su espacio de nombres XML utilizado en los elementos XML, puede importarlo fácilmente, no hay problema.

Usted necesita tener su XML algo parecido a esto:

<Catalog xmlns:dt="some-xml-namespace-here"> 
<Rec> 
    <ITEM dt:dt="string"/> 
    <QTY dt:dt="string">1</QTY> 
    <SUB dt:dt="string">1</SUB> 
    <CATALOG dt:dt="string">ABC123</CATALOG> 
    </Rec> 
    ..... 
</Catalog> 

Después de hacer esto, sus dos líneas de código como un encanto y los datos que se importa, no hay problema (en 5 mesas dentro del DataSet).

Marc

+0

Esto no se puede validar contra ningún esquema, pero si agrega xmlns = "dt" también, se puede crear un esquema que valide el xml. –

+0

Es cierto, pero el póster original no solicitó la validación, solo quiere importar el archivo a un conjunto de datos. Esto se puede lograr como lo demostré. –

0

Esto lo hará parseable. El espacio de nombres dt generalmente se refiere a xmlns: dt = "urn: schemas-microsoft-com: datatypes". Algo o alguien en mal estado el XML, pero si tiene que ser capaz de importar, sólo puede modificar los xmlns atributos en el elemento de catálogo, como se muestra:

  string xml = @"<Catalog xmlns=""dt"" xmlns:dt=""dt""> 
         <Rec> 
         <ITEM dt:dt=""string""/> 
         <QTY dt:dt=""string"">1</QTY> 
         <SUB dt:dt=""string"">1</SUB> 
         <CATALOG dt:dt=""string"">ABC123</CATALOG> 
         </Rec> 
         <Rec> 
         <ITEM dt:dt=""string""/> 
         <QTY dt:dt=""string"">1</QTY> 
         <SUB dt:dt=""string"">1</SUB> 
         <CATALOG dt:dt=""string"">ABC124</CATALOG> 
         </Rec> 
         <Rec> 
         <ITEM dt:dt=""string""/> 
         <QTY dt:dt=""string"">1</QTY> 
         <SUB dt:dt=""string"">1</SUB> 
         <CATALOG dt:dt=""string"">ABC125</CATALOG> 
         </Rec> 
         </Catalog>"; 

     DataSet ds = new DataSet("Whatev"); 

     TextReader txtReader = new StringReader(xml); 
     XmlReader reader = new XmlTextReader(txtReader); 
     ds.ReadXml(reader); 
     Debug.Assert(ds.Tables.Count ==5); 
     Debug.Assert((string)ds.Tables[2].Rows[0][0] == "string"); 
     Debug.Assert((string)ds.Tables[3].Rows[0][1] == "1"); 

también Marc es correcta, pero con la definición anterior se puede generar un esquema coincidente:

<xs:schema xmlns:dt="dt" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="dt" xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:element name="Catalog"><xs:complexType> <xs:sequence><xs:element maxOccurs="unbounded" name="Rec"><xs:complexType><xs:sequence><xs:element name="ITEM"><xs:complexType><xs:attribute ref="dt:dt" use="required" /></xs:complexType></xs:element><xs:element name="QTY"><xs:complexType> 
       <xs:simpleContent><xs:extension base="xs:unsignedByte"><xs:attribute ref="dt:dt" use="required" /></xs:extension></xs:simpleContent></xs:complexType> 
      </xs:element><xs:element name="SUB"><xs:complexType><xs:simpleContent><xs:extension base="xs:unsignedByte"><xs:attribute ref="dt:dt" use="required" /></xs:extension></xs:simpleContent></xs:complexType></xs:element><xs:element name="CATALOG"><xs:complexType><xs:simpleContent><xs:extension base="xs:string"><xs:attribute ref="dt:dt" use="required" /></xs:extension></xs:simpleContent></xs:complexType></xs:element></xs:sequence></xs:complexType></xs:element></xs:sequence></xs:complexType></xs:element><xs:attribute name="dt" type="xs:string" /></xs:schema> 

El atributo "dt" es un atributo de referencia. Entonces, el xml no puede ser válido contra ningún esquema sin la declaración xmlns = "ds" también.

+0

No me deja pegar todo el esquema en ... –

+0

Tuve que eliminar todos los espacios en blanco del esquema para poder mostrarlo todo. –

+0

Como el archivo es generado automáticamente por otro programa, ¿hay alguna manera de especificar un esquema a través del programa C# antes de leer el archivo en el conjunto de datos? La razón por la que pregunto es que no quiero tener que (a menos que sea fácil hacerlo) tener que modificar el archivo xml para agregar un esquema para que mi software pueda leerlo; ¡Estoy tratando de automatizar esto sin intervención humana! :) Además, ¿cuál es la forma más fácil de crear un esquema? ¿Hay asistentes o software que pueden ayudar en esto? Gracias por su ayuda, muchachos :) –

1
DataSet ds = new DataSet("Whatev"); 
DataTable catalog = ds.Tables.Add("Catalog"); 
DataColumn recCol = catalog.Columns.Add("Rec"); 
DataTable rec = ds.Tables.Add("Rec"); 

rec.Columns.AddRange(new DataColumn[] { 
    new DataColumn("ITEM", typeof(string)), 
    new DataColumn("QTY", typeof(string)), 
    new DataColumn("SUB", typeof(string)), 
    new DataColumn("CATALOG", typeof(string)) 
});    

XmlDocument doc = new XmlDocument(); 
doc.LoadXml(xml); 
foreach (XmlNode recNode in doc.GetElementsByTagName("Rec")) 
{ 
    DataRow row = rec.Rows.Add(
     recNode["ITEM"].InnerText, 
     recNode["QTY"].InnerText, 
     recNode["SUB"].InnerText, 
     recNode["CATALOG"].InnerText); 
} 

Hay ya go. Ahora habrá dos tablas, Catálogo y Rec. Sospecho que solo quieres Rec, porque Catalog es inútil. Por lo que sólo eliminar el código de tabla de datos de catálogo, si ese es el caso, o añadir un atributo id cada fila catálogo y vincularlo a REC:

DataSet ds = new DataSet("Whatev"); 
DataTable catalog = ds.Tables.Add("Catalog"); 
DataColumn idCol = catalog.Columns.Add("Id"); 
DataTable rec = ds.Tables.Add("Rec"); 

rec.Columns.AddRange(new DataColumn[] { 
    new DataColumn("ITEM", typeof(string)), 
    new DataColumn("QTY", typeof(string)), 
    new DataColumn("SUB", typeof(string)), 
    new DataColumn("CATALOG", typeof(string)) 
}); 

catalog.ChildRelations.Add("catToRecRelation", idCol, rec.Columns["CATALOG"]); 

XmlDocument doc = new XmlDocument(); 
doc.LoadXml(xml); 
foreach (XmlNode recNode in doc.GetElementsByTagName("Rec")) 
{ 
    // Create id in parent Catalog node, based on CATALOG value 
    catalog.Rows.Add(recNode["CATALOG"].InnerText); 

    DataRow row = rec.Rows.Add(
    recNode["ITEM"].InnerText, 
    recNode["QTY"].InnerText, 
    recNode["SUB"].InnerText, 
    recNode["CATALOG"].InnerText); 
} 

var childRows = catalog.Rows[0].GetChildRows("catToRecRelation"); 
0

utilizo este código ...

para generar el XML:

// you need to create a datatable, from a sql query, linq, your choice... 
DataTable _dt = new DataTable(); 
// write the datatable with schema 
dt.WriteXml("datatable.xml", XmlWriteMode.WriteSchema); 

Para leer el código XML:

DataTable dt = new DataTable(); 
dt.Clear(); 
dt.ReadXml("datatable.xml", XmlReadMode.ReadSchema); 

El resultado tabla de datos se pueden complementar con estas funciones, de esta manera se puede convertir a IList, es necesario crear un objeto con el mismo patrón de columnas, es realmente más práctico de esta manera:

public IList<T> toList<T>(DataTable table) 
{ 
    List<T> list = new List<T>(); 
    T item; 
    Type listItemType = typeof(T); 

    for (int i = 0; i < table.Rows.Count; i++) 
    { 
     item = (T)Activator.CreateInstance(listItemType); 
     mapRow(item, table.Rows[i], listItemType); 
     list.Add(item); 
    } 
    return list; 
} 
private void mapRow(object vOb, System.Data.DataRow dr, Type type) 
{ 
    try 
    { 
     for (int col = 0; col < dr.Table.Columns.Count; col++) 
     { 
      var columnName = dr.Table.Columns[col].ColumnName; 
      var prop = type.GetProperty(columnName.ToUpper()); 
      object data = dr[col]; 
      prop.SetValue(vOb, data, null); 
     } 
    } 
    catch (Exception ex) 
    { 
     throw ex; 
    } 
} 

En realidad, estoy trabajando en una aplicación que usa XML generado a partir de tablas SQL. Básicamente, use las funciones anteriores, creo otra aplicación pequeña (para apoyar la primera) que escanee el paquete de XML (XML por tabla) y cree las capas de negocios, acceso, objeto y un control de flujo para una correcta escritura & leyendo el XML.

1

no se mucho ingles así que escribiré en español. Yo tenia el mismo problema y después de una continuación, ademas de probar muchas veces, encontré la solución en las siguientes lineas.

DataSet dataSet = new DataSet(); 
DataTable dataTable = new DataTable("table1"); 
dataTable.Columns.Add("col1", typeof(string)); 
dataSet.Tables.Add(dataTable); 

string xmlData = "<XmlDS><table1><col1>Value1</col1></table1><table1><col1>Value2</col1></table1></XmlDS>"; 

System.IO.StringReader xmlSR = new System.IO.StringReader(xmlData); 
dataSet.ReadXml(xmlSR, XmlReadMode.IgnoreSchema); 

for information mas Detallada pueden see this page http://msdn.microsoft.com/es-es/library/fx29c3yd(v=vs.110).aspx

Espero les AYUDE Como ami.

Saludos