【问题标题】:How to cast XPathEvalute when it can be XElement or XAttribute?当 XPathEvalute 可以是 XElement 或 XAttribute 时,如何转换它?
【发布时间】:2012-09-30 08:59:24
【问题描述】:

所以我有这个代码:

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>();

我遇到的问题是这段代码:

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

有时来自 XPathEvaluate 的对象可能是 XElement,然后强制转换不起作用。所以我需要的是一个适用于 XAttribute 和 XElement 的 Cast。

有什么建议吗?

【问题讨论】:

  • 有时项目可能是 XElement,然后是 .. - 此代码中的 item只能 是 XElement。使问题难以理解。
  • 很抱歉让您感到困惑。 XPathEvaluate 中的对象可能来自 XElement 或来自 XAttribute,具体取决于 xpath。

标签: c# .net xml xpath


【解决方案1】:

将您的 XPath 表达式 (shop.TitleXPath) 从更改为:

  someXPathExpression

  string(someXPathExpression)

那么你可以将代码简化为

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

完整的工作示例

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);


    }
}

当这个程序被执行时,相同的 XPath 表达式被应用到两个不同的 XML 文档上,不管string() 的参数第一次是属性,第二次是元素,我们得到正确的结果——写入控制台:

attribute value
element value

【讨论】:

  • @Spindel,查看更新后的答案——现在它包含一个完整的工作解决方案。
  • @Dimitre,请看下面我的解决方案。
【解决方案2】:

Dimitre 的解决方案如果未找到该元素则返回空字符串;我们无法将它与实际的空值区分开来。所以我不得不制作这个扩展方法,通过 XPath 查询处理多个结果,如果没有找到则返回空枚举:

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;
    }
}

【讨论】:

  • +1。但如果:else if( xObject is XText xText) { yield return xText.Value; }
【解决方案3】:

XElementXAttribute 都是XObject 的形式,所以如果XObject 类型的通用实例足以满足您的需求,请将您的Cast&lt;XAttribute&gt; 更改为Cast&lt;XObject&gt;

如果这不适用于您的特定情况,您可以使用 OfType&lt;XAttribute&gt; 或 OfType&lt;XElement&gt; 过滤其中一个,但这需要两次通过输入,一次过滤 @ 987654329@ 和第二遍过滤XAttribute

【讨论】:

    【解决方案4】:

    在进行强制转换之前,您可以使用如下代码检查类型:

    XElement e = item as XElement;
    XAttribute a = item as XAttribute;
    
    if(e != null)
       //item is of type XElement
    else
      //item is of type XAttribute
    

    【讨论】:

    • 好的,但我真的不明白如何使它适合我的代码。你能用我上面的代码做一个例子吗?
    猜你喜欢
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多