LINQ to JSON - SelectToken错误

时间:2016-05-10 20:23:48

标签: c# linq json.net linq-to-json

这是我正在使用的JSON字符串。

#include <type_traits>

enum class EventType {
  READ,
  WRITE,
  SIGNAL
};

class ReadEventHandle { };
class WriteEventHandle { };
class SignalEventHandle { };

ReadEventHandle re;
WriteEventHandle we;
SignalEventHandle se;

class EventHandle {

public:

  template <EventType type,  std::enable_if_t<type == EventType::READ>* = nullptr >
  ReadEventHandle* cast () { return &re; }

  template <EventType type, std::enable_if_t<type == EventType::WRITE>* = nullptr >
  WriteEventHandle* cast () { return &we; }

  template <EventType type, std::enable_if_t<type == EventType::SIGNAL>* = nullptr>
  SignalEventHandle* cast () { return &se; }
};

void* check() {
  return EventHandle().cast<EventType::READ>(); // Depending on cast argument, different pointers returned
}

我正在尝试获取SYMBOL,NAME,PRICE和&amp ;;的值列表。 AGG_VOLUME。到目前为止,这是我的代码:

string jsonText = "{
    "?xml" : {
        "@version" : "1.0",
        "@encoding" : "UTF-8",
        "@standalone" : "yes"
    },
    "Grid" : {
        "DataRow" : [{
                "DataItem" : [{
                        "@name" : "SYMBOL",
                        "#text" : "005930"
                    }, {
                        "@name" : "NAME",
                        "#text" : "Samsung Electronics"
                    }, {
                        "@name" : "PRICE",
                        "#text" : "1004.3"
                    }, {
                        "@name" : "VOLUME",
                        "#text" : "273.182"
                    }, {
                        "@name" : "AGG_VOLUME",
                        "#text" : "302.894"
                    }
                ]
            }, {
                "DataItem" : [{
                        "@name" : "SYMBOL",
                        "#text" : "AAPL"
                    }, {
                        "@name" : "NAME",
                        "#text" : "Apple Inc."
                    }, {
                        "@name" : "PRICE",
                        "#text" : "99"
                    }, {
                        "@name" : "VOLUME",
                        "#text" : "32936.4"
                    }, {
                        "@name" : "AGG_VOLUME",
                        "#text" : "33078.769"
                    }
                ]
            }, {
                "DataItem" : [{
                        "@name" : "SYMBOL",
                        "#text" : "MSFT"
                    }, {
                        "@name" : "NAME",
                        "#text" : "Microsoft Corporation"
                    }, {
                        "@name" : "PRICE",
                        "#text" : "42"
                    }, {
                        "@name" : "VOLUME",
                        "#text" : "103441.6"
                    }, {
                        "@name" : "AGG_VOLUME",
                        "#text" : "1324432.074"
                    }
                ]
            }
        ]
    }
}"
JObject feed = JObject.Parse(jsonText);

但我收到以下错误:

  

对象引用未设置为对象的实例。

我做错了什么?

2 个答案:

答案 0 :(得分:2)

JToken.SelectTokens()支持JSONPath query syntax。您可以使用此语法来执行所需的查询:

  • ".."是通配符递归下降运算符。因此,feed.SelectTokens("..DataItem")查找名为DataItem的所有JSON属性的值,无论它们在JSON层次结构中的位置。

  • "[?(@.@name == 'Value')]"使用值为@name的名为Value的属性查询数组中的对象。

因此,以下是您所需要的:

var feed = JObject.Parse(jsonText);

var query = from item in feed.SelectTokens("..DataItem")
            select new
            {
                SYMBOL = (string)item.SelectToken("[?(@.@name == 'SYMBOL')].#text"),
                NAME = (string)item.SelectToken("[?(@.@name == 'NAME')].#text"),
                PRICE = (string)item.SelectToken("[?(@.@name == 'PRICE')].#text"),
                AGG_VOLUME = (string)item.SelectToken("[?(@.@name == 'AGG_VOLUME')].#text")
            };
var list = query.ToList();

答案 1 :(得分:1)

您收到此错误是因为feed引用了不直接包含JObject属性的根DataItem。因此feed["DataItem"]返回null。然后,当您尝试取消引用此空表达式时,它会抛出NullReferenceException

您尝试获取的数据是JSON中的几个层,因此您的查询必须考虑到这一点。例如,要获取JSON中所有SYMBOL值的列表,您需要执行以下操作:

List<string> symbols = 
    feed.SelectToken("Grid.DataRow")
        .SelectMany(jt => jt["DataItem"])
        .Where(jt => (string)jt["@name"] == "SYMBOL")
        .Select(jt => (string)jt["#text"])
        .ToList();

小提琴:https://dotnetfiddle.net/jxZGZC