7

LINQ を使用して XML ファイルをカスタム オブジェクトに解析するときに、NULL 値がないようにしようとしています。

Scott Gu's blogでこれに対する優れた解決策を見つけましたが、何らかの理由で整数に対しては機能しません。同じ構文を使用したと思いますが、何かが足りないようです。ああ、何らかの理由で、ノードが空でない場合に機能します。

以下は私のコードの抜粋です。

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname")
        select new GrantAgresso()
        {
             Year = (int?)g.Element("yearnode") ?? 0,
             Subdomain = (string)g.Element("domainnode") ?? ""
        }).ToList();

エラーメッセージは次のとおりです。

入力文字列は、正しい形式ではありませんでした。

誰かが私が間違っていることについての手がかりを持っている場合は、助けてください:)

編集:XMLの一部(奇妙な名前ですが、選択によるものではありません)

<Agresso>
  <AgressoQE>
    <r3dim_value>2012</r3dim_value>
    <r0r0r0dim_value>L5</r0r0r0dim_value>
    <r7_x0023_province_x0023_69_x0023_V005>0</r7_x0023_province_x0023_69_x0023_V005>
    <r7_x0023_postal_code_x0023_68_x0023_V004 />
    <r7_x0023_country_x0023_67_x0023_V003>1004</r7_x0023_country_x0023_67_x0023_V003>
    <r7_x0023_communitydistrict_x0023_70_x0023_V006>0</r7_x0023_communitydistrict_x0023_70_x0023_V006>
  </AgressoQE>
</Agresso>
4

6 に答える 6

3

投げているのはこの式です:

(int?)g.Element("yearnode")

これは、要素のテキストノードの実際の値がである場合String.Emptyとそうでないnull場合で、空の文字列はの有効な形式ではないためInt32.Parse、試行されたキャストは失敗するためです。

要素がXMLから完全に欠落している場合、これは期待どおりに機能しますが、空のタグ<yearnode/>またはが存在する場合は<yearnode></yearnode>、例外が発生します。

于 2012-10-02T12:45:41.887 に答える
1

メッセージInput string was not in a correct formatはによってスローされたもののように見えるint.parse ()のでyearnode、値(nullではない)を持つが、整数値に正常に解析できない可能性があります。

このような何かがそれを修正するかもしれません:

List<GrantAgresso> lsResult = (from g in xml.Element("root").Elements("Elementname")
    let yearNode = g.Element("yearnode")
    select new GrantAgresso
    {
         Year = string.IsNullOrWhiteSpace(yearNode.Value) ? 0 : int.Parse(yearNode.Value),
         Subdomain = g.Element("domainnode").Value
    }).ToList();

注意すべき点がいくつかあります。

select new GrantAgresso-オブジェクト初期化子を使用するデフォルトのコンストラクターには括弧は必要ありません。

string.IsNullOrWhiteSpace-.net4.0で導入されました。3.5string.IsNullOrEmpty以前を使用している場合に使用してください

g.Element("domainnode").Value-常に文字列を返します

0ではなくYearにnullが必要な場合は、(int?)null代わりにを使用してください0

于 2012-10-02T12:47:06.770 に答える
1

年がnullまたは空の文字列の場合、「入力文字列が正しい形式ではありませんでした」という例外が発生します。値を読み取るための拡張メソッドを作成できます。以下のコードはテストしていませんが、ヒントが得られる場合があります。

public static ReadAs<T>(this XElement el, T defaultValue) {
  var v = (string)el; // cast string to see if it is empty

  if (string.IsNullOrEmpty(v)) // test
    return defaultValue;

  return (T)el; // recast to our type.
}
于 2012-10-02T12:45:03.367 に答える
1

あなたは付け加えられますWhere operator

.....
.Where(a => ! string.IsNullOrEmpty(a)).ToList();
于 2012-10-02T12:17:46.220 に答える
1

次の拡張メソッドは、要素が存在しない場合、要素が空である場合、または整数に解析できない文字列が含まれている場合の両方で 0 を返します。

    public static int ToInt(this XElement x, string name)
    {
        int value;
        XElement e = x.Element(name);
        if (e == null)
            return 0;
        else if (int.TryParse(e.Value, out value))
            return value;
        else return 0;
    }

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

...
Year = g.ToInt("r3dim_value"),
...

または、リフレクションのコストを考慮し、任意の値型の既定値を受け入れる準備ができている場合は、次の拡張メソッドを使用できます。

public static T Cast<T>(this XElement x, string name) where T : struct
{
    XElement e = x.Element(name);
    if (e == null)
        return default(T);
    else
    {
        Type t = typeof(T);
        MethodInfo mi = t.GetMethod("TryParse",
                                    BindingFlags.Public | BindingFlags.Static,
                                    Type.DefaultBinder,
                                    new Type[] { typeof(string), 
                                                 t.MakeByRefType() },
                                    null);
        var paramList = new object[] { e.Value, null };
        mi.Invoke(null, paramList);
        return (T)paramList[1]; //returns default(T), if couldn't parse
    }
}

そしてそれを使用します:

...
Year = g.Cast<int>("r3dim_value"),
...
于 2012-10-02T23:41:43.877 に答える
0

あなたの問題は、XElementからintへのキャストですか?XElementの文字列値(この場合はString.Empty)でint.Parseメソッドを使用します。次の場合、同じエラーが発生します。

XElement x = new XElement("yearnode", String.Empty);
int? a = (int?)x; // throws FormatException

これを回避するには、最初にXElementを文字列にキャストし、それがnullまたは空であるかどうかを確認し、int?にキャストしない場合に限ります。これを行うには、

Year = (int?)g.Element("yearnode") ?? 0,

Year = !string.IsNullOrEmpty((string)g.Element("yearnode")) ? (int?)g.Element("yearnode") : 0,

それはきれいではなく、文字列が正当でない場合でもスローされますが、要素が常に整数またはnull/空であると想定できる場合は機能します。

于 2012-10-02T13:04:45.943 に答える