[VB/C#] System.Xml.XmlException 無効な文字の対策

DevelopmentXML

VB/C# で XDocument.LoadParse メソッドを呼んだときに「型 ‘System.Xml.XmlException’ のハンドルされていない例外が System.Xml.dll で発生しました」・「追加情報:’ ‘ (16 進数値 0xXX) は無効な文字です。 行 XX、位置 XX。」のような例外を避けるための話です。

Xml.XmlException

GitHub など有名な開発者向けのサービスでも、このような例外を発生させる XML を出力していることは、よくあり、悩まされます。

原因

XML 内に改行やタブ以外の制御文字などが含まれているとこのような例外が発生します。ちなみに、IE で XML を表示しようとしてもエラーになります(Firefox などでは普通に表示できます)。

XML で有効な文字は次の通りのようです。

  • #x9
  • #xA
  • #xD
  • #x20-#xD7FF
  • #xE000-#xFFFD
  • #x10000-#x10FFFF

関連ページ: PRB: Parsing XML Containing Invalid Character May Raise ArgumentException

対策

読めることを優先し、これ以外の文字は削除してから XDocument.Parse メソッドを呼ぶようにします。もし、制御文字が重要な場合は、HTML エンコードするように書き換えてください。

Sanitize 関数が今回用意した、文字列から XML で無効な文字列を削除して返す関数です。

Visual Basic (VB.NET)

Sub Main()
Dim url = "http://example.jp/xml"
Dim client = New WebClient With {.Encoding = Text.Encoding.UTF8}
Dim xml = client.DownloadString(url)
Dim d = XDocument.Parse(Sanitize(xml))
End Sub
Private Function Sanitize(xml As String) As String
Dim sb = New Text.StringBuilder
For Each c In xml
Dim code = AscW(c)
If code = &H9 OrElse
code = &HA OrElse
code = &HD OrElse
(&H20 <= code AndAlso code <= &HD7FF) OrElse
(&HE000 <= code AndAlso code <= &HFFFD) OrElse
(&H10000 <= code AndAlso code <= &H10FFFF) Then
sb.Append(c)
End If
Next
Return sb.ToString
End Function

view raw
Module.vb
hosted with ❤ by GitHub

C#

static void Main(string[] args)
{
var url = "http://example.jp/xml";
var client = new WebClient() { Encoding = Encoding.UTF8 };
var xml = client.DownloadString(url);
var d = XDocument.Parse(Sanitize(xml));
}
private static string Sanitize(string xml)
{
var sb = new System.Text.StringBuilder();
foreach (var c in xml)
{
var code = (int)c;
if (code == 0x9 ||
code == 0xa ||
code == 0xd ||
(0x20 <= code && code <= 0xd7ff) ||
(0xe000 <= code && code <= 0xfffd) ||
(0x10000 <= code && code <= 0x10ffff))
{
sb.Append(c);
}
}
return sb.ToString();
}

view raw
Program.cs
hosted with ❤ by GitHub

DevelopmentXML

Posted by jz5