2012-09-30 17 views
9

así que tengo este código:Cómo ejecutar XPathEvalute cuando puede ser XElement o XAttribute?

List<PriceDetail> prices = 
       (from item in xmlDoc.Descendants(shop.DescendantXName) 
       select new PriceDetail 
       { 
        Price = GetPrice(item.Element(shop.PriceXPath).Value), 
        GameVersion = GetGameVersion(((IEnumerable)item.XPathEvaluate(shop.TitleXPath)).Cast<XAttribute>().First<XAttribute>().Value, item.Element(shop.PlatformXPath).Value), 
        Shop = shop, 
        Link = item.Element(shop.LinkXPath).Value, 
        InStock = InStock(item.Element(shop.InStockXPath).Value) 
       }).ToList<PriceDetail>(); 

El problema que tengo es este código:

((IEnumerable)item.XPathEvaluate(shop.TitleXPath)).Cast<XAttribute>().First<XAttribute>().Value 

A veces el objeto de XPathEvaluate podría ser XElement y luego el casting no funciona. Entonces, lo que necesito es un Cast que funcione tanto con XAttribute como con XElement.

¿Alguna sugerencia?

+0

_Sometimes el tema podría ser XElement y luego .._ - el 'item' en este código puede _only_ be XElement. Hace la pregunta difícil de seguir. –

+0

Disculpa por confundirte. El objeto de XPathEvaluate podría ser de XElement o de XAttribute que depende de xpath. – Spindel

Respuesta

12

cambio su expresión XPath (shop.TitleXPath) de:

someXPathExpression 

a:

string(someXPathExpression) 

A continuación, se puede simplificar el código para simplemente:

string result = item.XPathEvaluate(shop.TitleXPath) as string; 

ejemplo de trabajo completa:

using System; 
using System.IO; 
using System.Xml.Linq; 
using System.Xml.XPath; 

class TestXPath 
{ 
    static void Main(string[] args) 
    { 

     string xml1 = 
@"<t> 
<a b='attribute value'/> 
<c> 
    <b>element value</b> 
</c> 
<e b='attribute value'/> 
</t>"; 

     string xml2 = 
@"<t> 
<c> 
    <b>element value</b> 
</c> 
<e b='attribute value'/> 
</t>"; 

     TextReader sr = new StringReader(xml1); 
     XDocument xdoc = XDocument.Load(sr, LoadOptions.None); 

     string result1 = xdoc.XPathEvaluate("string(/*/*/@b | /*/*/b)") as string; 

     TextReader sr2 = new StringReader(xml2); 
     XDocument xdoc2 = XDocument.Load(sr2, LoadOptions.None); 

     string result2 = xdoc2.XPathEvaluate("string(/*/*/@b | /*/*/b)") as string; 

     Console.WriteLine(result1); 
     Console.WriteLine(result2); 


    } 
} 

Cuando se ejecuta este programa, se aplica la misma expresión XPath en dos diferentes Documentos XML y, independientemente del hecho de que el argumento a string() es un atributo la primera vez y es un elemento en el segundo, obtenemos los resultados correctos - w RENON a la consola:

attribute value 
element value 
+0

No funcionó: término de expresión inválido 'cadena'. – Spindel

+0

@Spindel, vea la respuesta actualizada, ahora contiene una solución de trabajo completa. –

+0

Ahora veo. ¡Gracias! – Spindel

1

Antes de realizar el reparto se puede comprobar el tipo utilizando un código como el siguiente:

XElement e = item as XElement; 
XAttribute a = item as XAttribute; 

if(e != null) 
    //item is of type XElement 
else 
    //item is of type XAttribute 
+0

Ok, pero realmente no entiendo cómo puedo hacer que encaje en mi código. ¿Podría hacer un ejemplo con mi código de arriba? – Spindel

6

XElement y XAttribute son ambas formas de XObject, por lo que si una instancia genérica de tipo XObject será suficiente para sus necesidades, cambiar su <XAttribute> moldeada en Cast <XObject>.

Si eso no funcionará para su situación específica, que hacen uso de OfType <XAttribute> o OfType <XElement> que filtrar el uno o el otro, pero eso requeriría dos pasadas sobre la entrada, uno para filtrar XElement y un segundo pase para filtrar por XAttribute.

3

La solución de Dimitre devuelve cadena vacía si el elemento no se encuentra; no podemos distinguirlo del valor real vacío. Así que tuve que hacer este método de extensión que se encarga de múltiples resultados por consulta XPath y devuelve la enumeración vacía si no se encuentra nada:

public static IEnumerable<string> GetXPathValues(this XNode node, string xpath) 
{ 
    foreach (XObject xObject in (IEnumerable)node.XPathEvaluate(xpath)) 
    { 
     if (xObject is XElement) 
      yield return ((XElement)xObject).Value; 
     else if (xObject is XAttribute) 
      yield return ((XAttribute)xObject).Value; 
    } 
} 
Cuestiones relacionadas