11

So I have this code:

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

The problem I have is this code:

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

Sometimes the object from XPathEvaluate could be XElement and then the casting doesn't work. So what I need is a Cast that works with both XAttribute and XElement.

Any suggestion?

4

4 に答える 4

16

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 式が 2 つの異なる XML ドキュメントに適用され、引数 tostring()が最初は属性で、2 回目は要素であるという事実に関係なく、正しい結果が得られます。コンソール:

attribute value
element value
于 2012-09-30T14:04:01.967 に答える
10

要素が見つからない場合、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;
    }
}
于 2014-02-21T13:00:29.587 に答える
7

XElementXAttributeは両方とも の形式でXObjectあるため、必要に応じて type のジェネリック インスタンスで十分な場合は、 Castを CastXObjectに変更します。<XAttribute><XObject>

特定の状況でそれがうまくいかない場合は、 OfType<XAttribute>または OfTypeを使用してどちらか一方<XElement>をフィルター処理しますが、入力に対して 2 つのパスが必要になりXElementますXAttribute

于 2012-11-27T18:41:20.973 に答える
1

キャストを行う前に、次のようなコードを使用して型を確認できます。

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

if(e != null)
   //item is of type XElement
else
  //item is of type XAttribute
于 2012-09-30T09:05:11.960 に答える