トップ回答者
using System.Xml のバグ?

質問
-
お世話になっております。次のコードを実行すると、XMLの読み込みエラーとなってしまいます。これはSystem.xmlのバグではないでしょうか?ほかの処理系に食わせてもxml is validで正しいと判定されます。
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using System.Net;
using System.Collections.Specialized;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Text;
namespace XMLLoadTest
{
class Program
{
static void Main(string[] args)
{
string FileURL = "http://disclosure.edinet-fsa.go.jp/taxonomy/jplvh/2013-08-31/jplvh_rt_2013-08-31.xsd";
DateTime lastModified = DateTime.MinValue;
if (System.IO.File.Exists(FileURL))
{
return;
}
WebClient client = new WebClient();
string content = client.DownloadString(FileURL);
//Test for urls that return empty text data
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(content);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
実行:
B:\XMLLoadTest\XMLLoadTest\bin\Debug>XMLLoadTest.exe
System.Xml.XmlException: 行 32、位置 10 にある開始タグ 'link:definition' と終了タグ 'link:roleType' が対応していません。 行 37、位置 9。
場所 System.Xml.XmlTextReaderImpl.Throw(Exception e)
場所 System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
場所 System.Xml.XmlTextReaderImpl.ThrowTagMismatch(NodeData startTag)
場所 System.Xml.XmlTextReaderImpl.ParseEndElement()
場所 System.Xml.XmlTextReaderImpl.ParseElementContent()
場所 System.Xml.XmlTextReaderImpl.Read()
場所 System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
場所 System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
場所 System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
場所 System.Xml.XmlDocument.Load(XmlReader reader)
場所 System.Xml.XmlDocument.LoadXml(String xml)
場所 XMLLoadTest.Program.Main(String[] args) 場所 B:\XMLLoadTest\XMLLoadTest\Program.cs:行 43ちなみに、.NET 2.0/3.0/4.0すべて同じです。
回答
-
DownloadStringでエンコードが一致していないので文字化けしてます。
文字化けしている状態でXML解析しようとしてエラーになってます。エンコード指定してDownLoadStringするか、DownloadDataでバイト配列として取り出したものを文字列化せずに渡しましょう。(OpenReadのStreamでもいいです)
WebClient client = new WebClient(); client.Encoding = System.Text.Encoding.UTF8; string content = client.DownloadString(FileURL); var bs = client.DownloadData(FileURL); System.IO.MemoryStream ms = new MemoryStream(bs); try { XmlDocument doc = new XmlDocument(); doc.Load(ms); //doc.Load(client.OpenRead(FileURL)); } catch (Exception e) { Console.WriteLine(e.ToString()); }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
-
補足します。
このメソッドは、リソースをダウンロードした後、Encodingプロパティに指定されたエンコーディングを使用して、リソースをStringに変換します。
と説明されています。更にWebClient.Encoding プロパティは
このプロパティの既定値は、Default によって返されるエンコーディングです。
と説明されています。ここでEncoding.Defaultは日本語版WindowsであればShift-JISです。しかし実際のコンテンツはUTF-8のようです。
結局のところ、System.Xmlのバグでもなんでもなく、WebClient.DownloadStringメソッドの使い方誤りです。
SurferOnWwwさんが書かれているようにXmlDocumentクラスにはダウンロードを行うLoad()メソッドもありますのでこちらを使うべきですが、あえてWebClientクラスを使うのであれば、WebClient.OpenRead()メソッドを用いてStreamを得て、XmlDocument.Load()メソッドにそのStreamを渡すことです。というのもXML仕様にはエンコーディングに関する取り決めもあるため、validなxmlである限り呼び出し側で明示的に指定する必要はありません。
-
> 次のコードを実行すると、XMLの読み込みエラーとなってしまいます。
> これはSystem.xmlのバグではないでしょうか?単純に以下のようにして問題ないのでバグではないと思いますが? sample2.xml はブラウザで FileURL の url にアクセスして表示された内容そのままのファイルです。
XmlDocument document = new XmlDocument(); document.Load(@"C:\Users\...省略...\ConsoleApplication5\sample2.xml"); Console.WriteLine(document.OuterXml);
原因究明には、疑っている部分以外の余計なところをどんどん削除していって試してみることをお勧めします。
【追伸】
ファイルから読む代わりに、以下のように直接 URL を指定しても OK でした。
document.Load("http://disclosure.edinet-fsa.go.jp/taxonomy/jplvh/2013-08-31/jplvh_rt_2013-08-31.xsd");
- 編集済み SurferOnWww 2015年10月18日 3:46 追伸追加
- 回答としてマーク 星 睦美 2015年10月30日 5:34
すべての返信
-
DownloadStringでエンコードが一致していないので文字化けしてます。
文字化けしている状態でXML解析しようとしてエラーになってます。エンコード指定してDownLoadStringするか、DownloadDataでバイト配列として取り出したものを文字列化せずに渡しましょう。(OpenReadのStreamでもいいです)
WebClient client = new WebClient(); client.Encoding = System.Text.Encoding.UTF8; string content = client.DownloadString(FileURL); var bs = client.DownloadData(FileURL); System.IO.MemoryStream ms = new MemoryStream(bs); try { XmlDocument doc = new XmlDocument(); doc.Load(ms); //doc.Load(client.OpenRead(FileURL)); } catch (Exception e) { Console.WriteLine(e.ToString()); }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
-
> 次のコードを実行すると、XMLの読み込みエラーとなってしまいます。
> これはSystem.xmlのバグではないでしょうか?単純に以下のようにして問題ないのでバグではないと思いますが? sample2.xml はブラウザで FileURL の url にアクセスして表示された内容そのままのファイルです。
XmlDocument document = new XmlDocument(); document.Load(@"C:\Users\...省略...\ConsoleApplication5\sample2.xml"); Console.WriteLine(document.OuterXml);
原因究明には、疑っている部分以外の余計なところをどんどん削除していって試してみることをお勧めします。
【追伸】
ファイルから読む代わりに、以下のように直接 URL を指定しても OK でした。
document.Load("http://disclosure.edinet-fsa.go.jp/taxonomy/jplvh/2013-08-31/jplvh_rt_2013-08-31.xsd");
- 編集済み SurferOnWww 2015年10月18日 3:46 追伸追加
- 回答としてマーク 星 睦美 2015年10月30日 5:34
-
補足します。
このメソッドは、リソースをダウンロードした後、Encodingプロパティに指定されたエンコーディングを使用して、リソースをStringに変換します。
と説明されています。更にWebClient.Encoding プロパティは
このプロパティの既定値は、Default によって返されるエンコーディングです。
と説明されています。ここでEncoding.Defaultは日本語版WindowsであればShift-JISです。しかし実際のコンテンツはUTF-8のようです。
結局のところ、System.Xmlのバグでもなんでもなく、WebClient.DownloadStringメソッドの使い方誤りです。
SurferOnWwwさんが書かれているようにXmlDocumentクラスにはダウンロードを行うLoad()メソッドもありますのでこちらを使うべきですが、あえてWebClientクラスを使うのであれば、WebClient.OpenRead()メソッドを用いてStreamを得て、XmlDocument.Load()メソッドにそのStreamを渡すことです。というのもXML仕様にはエンコーディングに関する取り決めもあるため、validなxmlである限り呼び出し側で明示的に指定する必要はありません。