Pregunta

Tengo el siguiente archivo xml y parece que no puedo entender cómo obtener el valor en los elementos (que están enterrados en un CDATA). Estoy tratando de usar linq to xml para esto. Si alguien sabe cómo convertiría esto en un "Producto" objeto (supongamos que tenemos un objeto producto que tiene propiedades con los mismos nombres que los elementos). Gracias de antemano.

bob

<CNETResponse realm="cnet" version="1.0" xmlns="http://api.cnet.com/rest/v1.0/ns" xmlns:xlink="http://www.w3.org/1999/xlink">
<TechProduct id="33517677">
    <Name><![CDATA[Nikon CoolPix L20 (deep red)]]></Name>
    <Topic id="1670"></Topic>
    <ImageURL width="60"><![CDATA[http://i.i.com.com/cnwk.1d/sc/33517677-2-60-0.gif]]></ImageURL>
</TechProduct>
</CNETResponse>
¿Fue útil?

Solución

El problema son los espacios de nombres, por ejemplo, algo así como:

XNamespace ns = "http://api.cnet.com/rest/v1.0/ns";
XElement techProd = doc.Root.Element(ns + "TechProduct");

Product product = new Product {
    Id = (int)techProd.Attribute("id"),
    Name = techProd.Element(ns + "Name").Value,
    Topic = techProd.Element(ns + "Topic").Value,
    TopicId = (int)techProd.Element(ns + "Topic").Attribute("id"),
    ImageUrl = techProd.Element(ns + "ImageURL").Value,
    ImageWidth = (int)techProd.Element(ns + "ImageURL").Attribute("width"),
};

También puede preferir XmlSerializer , algo así como:

XmlSerializer ser = new XmlSerializer(typeof(CnetResponse));
CnetResponse response = (CnetResponse)ser.Deserialize(new StringReader(xml));
TechProduct product = response.TechProduct;

Con definiciones de clase como:

[Serializable, XmlRoot("CNETResponse", Namespace = CnetResponse.Namespace)]
public class CnetResponse {
    public const string Namespace = "http://api.cnet.com/rest/v1.0/ns";
    public TechProduct TechProduct { get; set; }
}
[Serializable, XmlType(Namespace = CnetResponse.Namespace)]
public class TechProduct
{
    [XmlAttribute("id")]
    public int Id { get; set; }
    public string Name {get;set;}
    public Topic Topic { get; set; }
    [XmlElement("ImageURL")]
    public Image Image { get; set; }        
}
[Serializable, XmlType(Namespace = CnetResponse.Namespace)]
public class Topic {
    [XmlAttribute("id")]
    public int Id { get; set; }
    [XmlText]
    public string Text {get;set;}
}
[Serializable, XmlType(Namespace = CnetResponse.Namespace)]
public class Image {
    [XmlAttribute("width")]
    public int Width { get; set; }
    [XmlText]
    public string Url {get;set;}
}

O, como alternativa, simplemente ejecute el xml a través de xsd.exe para obtener el código C # adecuado:

xsd foo.xml
xsd foo.xsd /classes

Otros consejos

Suponiendo que su clase Product tiene el constructor utilizado aquí, intente esto, donde rawXml es el XML de respuesta CNET:

XElement cnetResponse = XElement.Parse(rawXml);

IEnumerable<NameQty> products =
    from e in cnetResponse.Descendants("TechProduct")
    select new Product(
        (string)e.Element("Name"),
        (int)e.Element("Topic").Attribute("id"),
        (string)e.Element("ImageURL")
    );

foreach(Product p in products)
{
    // do stuff
}

No tengo acceso a una máquina en la que probar esto, así que no garantizo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top