3

XML ファイルを通過する while ループがあり、ノード「url」の 1 つに無効な値が含まれていることがあります。これに try-catch ステートメントを配置して、無効な値をキャッチします。問題は、無効な値が取得されるたびに while ループが強制終了され、プログラムがそのループの外で続行されることです。無効な値が見つかった場合に XML ファイルの残りの部分を読み続けるには、while ループが必要です。

これが私のコードです:

        XmlTextReader reader = new XmlTextReader(fileName);
        int tempInt;

        while (reader.Read())
        {
            switch (reader.Name)
            {
                case "url":
                    try
                    {
                        reader.Read();
                        if (!reader.Value.Equals("\r\n"))
                        {
                            urlList.Add(reader.Value);
                        }
                    }
                    catch
                    {                            
                        invalidUrls.Add(urlList.Count);   
                    }
                    break;
            }
        }

残りの switch ステートメントは関係ないため、含めないことにしました。これが私の XML のサンプルです。

<?xml version="1.0"  encoding="ISO-8859-1" ?>
<visited_links_list>
    <item>
        <url>http://www.grcc.edu/error.cfm</url>
        <title>Grand Rapids Community College</title>
        <hits>20</hits>
        <modified_date>10/16/2012 12:22:37 PM</modified_date>
        <expiration_date>11/11/2012 12:22:38 PM</expiration_date>
        <user_name>testuser</user_name>
        <subfolder></subfolder>
        <low_folder>No</low_folder>
        <file_position>834816</file_position>
     </item>
</visited_links_list>

コード全体で発生する例外は、次のようなものです。

「' '、16 進値 0x05 は無効な文字です。3887 行目、13 番目の位置。」

4

4 に答える 4

3

観察:

エントリごとにreader.Read() 2 回呼び出しています。に 1while()回、 内に 1 回case。本当にレコードをスキップするつもりですか? これにより、ソース XML に奇数のエントリがある場合に例外が発生します ( XMLストリームreader.Read()内のポインタが次の項目に進むため) 。try...catch

それ以上:

reader.Read(); /// might return false, but no exception, so keep going...

if (!reader.Value.Equals("\r\n")) /// BOOM if the previous line returned false, which you ignored
{ 
    urlList.Add(reader.Value); 
} 
/// reader is now in unpredictable state

編集

小説の長さの答えを書くリスクがあります...

表示されるエラー

「' '、16 進値 0x05 は無効な文字です。3887 行目、13 番目の位置。」

ソース XML の形式が正しくなく、^E指定された位置に (ASCII 0x05) が含まれていることを示します。私はその行を見たいと思います。このファイルをベンダーまたはサービスから取得している場合は、ベンダーまたはサービスにコードを修正してもらう必要があります。それを修正し、XML 内のその他の不正なコンテンツを修正すると、発生している問題が修正されます。

それが修正されると、元のコードが機能するはずです。ただし、XmlTextReaderこれを使用するのは最も堅牢なソリューションではなく、Visual Studio が喜んで生成するコードを作成する必要があります。

VS2012 の場合 (VS2010 はもうインストールしていませんが、同じプロセスである必要があります):

  • XML のサンプルをソリューションに追加する

  • そのファイルのプロパティで、CustomTool を "MSDataSetGenerator" (引用符なし) に設定します。

  • IDE は、XML 内の各項目のフィールドを持つシリアル化可能なクラスを含む .designer.cs ファイルを生成する必要があります。(そうでない場合は、ソリューション エクスプローラーで XML ファイルを右クリックし、[カスタム ツールの実行] を選択します。)

ここに画像の説明を入力

  • 次のようなコードを使用して、実行時にサンプルと同じスキーマで XML を読み込みます。

    /// make sure the XML doesn't have errors, such as non-printable characters
    private static bool IsXmlMalformed(string fileName)
    {
        var reader = new XmlTextReader(fileName);
        var result = false;
    
        try
        {
            while (reader.Read()) ;
        }
        catch (Exception e)
        {
            result = true;
        }
    
        return result;
    }
    
    /// Process the XML using deserializer and VS-generated XML proxy classes
    private static void ParseVisitedLinksListXml(string fileName, List<string> urlList, List<int> invalidUrls)
    {
        if (IsXmlMalformed(fileName))
            throw new Exception("XML is not well-formed.");
    
        using (var textReader = new XmlTextReader(fileName))
        {
            var serializer = new XmlSerializer(typeof(visited_links_list));
    
            if (!serializer.CanDeserialize(textReader))
                throw new Exception("Can't deserialize this XML. Make sure the XML schema is up to date.");
    
            var list = (visited_links_list)serializer.Deserialize(textReader);
    
            foreach (var item in list.item)
            {
                if (!string.IsNullOrEmpty(item.url) && !item.url.Contains(Environment.NewLine))
                    urlList.Add(item.url);
                else
                    invalidUrls.Add(urlList.Count);
            }
        }
    }
    

これは、Windows SDK に含まれている XSD.exe ツールでも実行できます。

于 2012-10-16T21:43:44.203 に答える
1

reader例外がスローされた後、障害のある状態のままになっているように感じます((ではなく、のreader.Read();内部で)例外が発生した行である可能性が高いためです。その後、inは何も返さず、終了します。switchwhilereader.Read()while

私はコンソールアプリで単純なswitchことを行い、その中でキャッチと例外を実行しましたが、包含ループは続行されます。

var s = "abcdefg";
foreach (var character in s)
{
    switch (character)
    {
        case 'c':
            try
            {
                throw new Exception("c sucks");
            }
            catch
            {
                // Swallow the exception and move on?
            }
            break;
        default:
            Console.WriteLine(character);
            break;
    }
}

コードをウォークスルーすると、例外がキャッチさreader.Read()れた後に実行しようとしますか?while

于 2012-10-16T21:35:09.837 に答える
-1

使い続ける

while (reader.Read())
        {
            switch (reader.Name)
            {
                case "url":
                    try
                    {
                        reader.Read();
                        if (!reader.Value.Equals("\r\n"))
                        {
                            urlList.Add(reader.Value);
                        }
                    }
                    catch
                    {
                        invalidUrls.Add(urlList.Count);
                        continue;
                    }
                    break;
            }
        }
于 2012-10-16T21:30:45.960 に答える