0

私は最近Linqを使い始めましたが、現在、Linqを使用して、高度にネストされたXMLファイル(制御できません)を解析しようとしています。ただし、以下のステートメントを実行しようとすると、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というエラーが発生します。

問題は「City」ラインにあります。cityプロパティのデータは、xml構造のprospect / contactinfo / City/Answerから取得されます。

ただし、このフィールドは必須ではないため、XMLに都市/回答ノードがない場合があります。そのため、「city」ノードが存在しないためにエラーが発生し、そのノードで「.Element()」を呼び出そうとしています。ノードレベルが1つだけ下がっている場合(つまり、必要なデータが都市にあり、都市が唯一のノードが欠落している場合)、この問題の解決策をたくさん見つけました。

しかし、それが2レベル下にある場合(つまり、存在しないノードの子ノードを取得しようとしている場合)、解決策を見つけることができませんでした。

質問が十分に明確に表現されていることを願っています。

よろしく、モーテン

            var prospects = (from prospect in xdoc.Descendants("PROSPECT")
                        select new Prospect {
                            ProspectID = (string) prospect.Element("PROSPECTINFO").Element("PROSPECT_ID"),
                            Name = (string) prospect.Element("PERSONALINFO").Element("FIRSTNAME")+ " " + prospect.Element("PERSONALINFO").Element("SURNAME"),
                            address = (string) prospect.Element("CONTACTINFO").Element("ADDRESSLINE1").Element("ANSWER"),
                            zipCode = (string)prospect.Element("CONTACTINFO").Element("POSTALCODE").Element("ANSWER").Value,
                            City = (string) prospect.Element("CONTACTINFO").Element("CITY").Element("ANSWER"),                                
                        }).ToList();
4

3 に答える 3

5

1つのオプションは、Elementsの代わりに使用することですElement。これは、単一の要素または要素のコレクション内のすべての要素(オプションで指定された名前)を検索する拡張メソッドです。したがって、これを繰り返し使用すると、一致する要素がない場合、最後に0個の要素のコレクションが作成されます。その要素またはnullを取得するために使用FirstOrDefaultすると、文字列変換は必要な処理を実行します。

// Still use Element for CONTACTINFO as presumably that's a required element
City = (string) prospect.Element("CONTACTINFO")
                        .Elements("CITY")
                        .Elements("ANSWER")
                        .FirstOrDefault()

そうすれば、条件付きコードを書く必要はありません-それはすべてドロップアウトするだけです。

ChrisFが提案する種類のチェックに対するこれの最大の利点は、ナビゲーションパスが長くなるかどうかです。パスの6つの部分があり、それらのすべてがオプションであると想像してください。5つのチェック(最初に「a」、次に「ab」、次に「abc」など)が必要で、その後に実際の「フェッチ」が続きます。一方、このスキームでElementsは、新しいナビゲーションリンクごとに1つの呼び出しを追加するだけです。

于 2012-08-06T15:52:12.347 に答える
2

いずれかのノードがnullになる可能性がある場合は、コードでそれに対処する必要があります。

あなたは「CITY」ノードについて言及しているので、それを例として取り上げます。

var prospects = (from prospect in xdoc.Descendants("PROSPECT")
                    select new Prospect {
                        ProspectID =
 (string)prospect.Element("PROSPECTINFO").Element("PROSPECT_ID"),
                        Name =
 (string)prospect.Element("PERSONALINFO").Element("FIRSTNAME")+ " " + prospect.Element("PERSONALINFO").Element("SURNAME"),
                        address =
 (string)prospect.Element("CONTACTINFO").Element("ADDRESSLINE1").Element("ANSWER"),
                        zipCode =
 (string)prospect.Element("CONTACTINFO").Element("POSTALCODE").Element("ANSWER").Value,
                        City =
 prospect.Element("CONTACTINFO").Element("CITY") != null ?
     (string)prospect.Element("CONTACTINFO").Element("CITY").Element("ANSWER") :
     string.Empty,
   }).ToList();

要素を区別する前に、要素がnullでないことを確認する必要があります。次に、要素がnullの場合は、プロパティに割り当てるデフォルト値を選択します。

nullになる可能性のあるすべての要素に対してこれを繰り返します。

チェックをメソッドに入れること(Mikeが提案するように)は、コードをクリーンに保つための良い方法です。また、チェックを非常に簡単に拡張できることも意味します。

于 2012-08-06T15:50:49.720 に答える
1

NULLチェックで指定した要素の値を取得するジェネリック関数を作成します。次に例を示します。

public string GetXMLElementValue(XmlElement xElem, params string[] elementsNest)
{
    XmlElement tempElem = xElem;

    foreach (string s in elementsNest)
    {
        if (tempElem.Element(s) == null)
            return string.Empty;
        else
            tempElem = tempElem.Element(s);
    }

    return (string) tempElem;
}

次に、次のように使用できます。

var prospects = (from prospect in xdoc.Descendants("PROSPECT")
    select new Prospect {
        . . .
        City = GetXMLElementValue(prospect, "CONTACTINFO", "CITY", "ANSWER"),          
}).ToList();

注:これはテストされていないコードですが、一般的な考え方を示しています。要素で「.Value」または他のメソッドを呼び出すかどうかを指定するために、関数に他のパラメーターが必要になる場合があります。

于 2012-08-06T16:17:00.220 に答える