無効なXML文字を含む文字列があります。文字列を解析する前に無効なXML文字をエスケープ(または削除)するにはどうすればよいですか?
無効なXML文字を削除する方法として、 XmlConvert.IsXmlChar メソッドを使用することをお勧めします。 .NET Framework 4以降に追加され、Silverlightでも表示されます。以下に小さなサンプルを示します。
void Main() {
string content = "\v\f\0";
Console.WriteLine(IsValidXmlString(content)); // False
content = RemoveInvalidXmlChars(content);
Console.WriteLine(IsValidXmlString(content)); // True
}
static string RemoveInvalidXmlChars(string text) {
var validXmlChars = text.Where(ch => XmlConvert.IsXmlChar(ch)).ToArray();
return new string(validXmlChars);
}
static bool IsValidXmlString(string text) {
try {
XmlConvert.VerifyXmlChars(text);
return true;
} catch {
return false;
}
}
無効なXML文字をエスケープする方法として、 XmlConvert.EncodeName メソッドを使用することをお勧めします。以下に小さなサンプルを示します。
void Main() {
const string content = "\v\f\0";
Console.WriteLine(IsValidXmlString(content)); // False
string encoded = XmlConvert.EncodeName(content);
Console.WriteLine(IsValidXmlString(encoded)); // True
string decoded = XmlConvert.DecodeName(encoded);
Console.WriteLine(content == decoded); // True
}
static bool IsValidXmlString(string text) {
try {
XmlConvert.VerifyXmlChars(text);
return true;
} catch {
return false;
}
}
更新:エンコード操作により、ソース文字列の長さ以上の長さの文字列が生成されることに注意してください。エンコードされた文字列を長さ制限のある文字列列のデータベースに保存し、アプリ内のソース文字列の長さを検証してデータ列の制限に適合する場合に重要になる場合があります。
SecurityElement.Escape を使用します
using System;
using System.Security;
class Sample {
static void Main() {
string text = "Escape characters : < > & \" \'";
string xmlText = SecurityElement.Escape(text);
//output:
//Escape characters : < > & " '
Console.WriteLine(xmlText);
}
}
Xmlを作成している場合は、フレームワークが提供するクラスを使用してxmlを作成します。エスケープなどを気にする必要はありません。
Console.Write(new XElement("Data", "< > &"));
出力します
<Data>< > &</Data>
不正な形式のXMLファイルを読み取る必要がある場合は、しないでくださいse 正規表現。代わりに、 Html Agility Pack を使用してください。
Irishmanが提供するRemoveInvalidXmlCharsメソッドは、代理文字をサポートしていません。テストするには、次の例を使用します。
static void Main()
{
const string content = "\v\U00010330";
string newContent = RemoveInvalidXmlChars(content);
Console.WriteLine(newContent);
}
これは空の文字列を返しますが、返すべきではありません!文字 + 103 は有効なXML文字であるため、「\ U00010330」を返す必要があります。
代理文字をサポートするには、次の方法を使用することをお勧めします。
public static string RemoveInvalidXmlChars(string text)
{
if (string.IsNullOrEmpty(text))
return text;
int length = text.Length;
StringBuilder stringBuilder = new StringBuilder(length);
for (int i = 0; i < length; ++i)
{
if (XmlConvert.IsXmlChar(text[i]))
{
stringBuilder.Append(text[i]);
}
else if (i + 1 < length && XmlConvert.IsXmlSurrogatePair(text[i + 1], text[i]))
{
stringBuilder.Append(text[i]);
stringBuilder.Append(text[i + 1]);
++i;
}
}
return stringBuilder.ToString();
}
次に、上記のメソッドRemoveInvalidXmlCharsの最適化バージョンを示します。このメソッドは、呼び出しごとに新しい配列を作成しないため、GCに不必要に負荷がかかります。
public static string RemoveInvalidXmlChars(string text)
{
if (text == null)
return text;
if (text.Length == 0)
return text;
// a bit complicated, but avoids memory usage if not necessary
StringBuilder result = null;
for (int i = 0; i < text.Length; i++)
{
var ch = text[i];
if (XmlConvert.IsXmlChar(ch))
{
result?.Append(ch);
}
else if (result == null)
{
result = new StringBuilder();
result.Append(text.Substring(0, i));
}
}
if (result == null)
return text; // no invalid xml chars detected - return original text
else
return result.ToString();
}
// Replace invalid characters with empty strings.
Regex.Replace(inputString, @"[^\w\.@-]", "");
正規表現パターン[^\w。@-]は、Word文字、ピリオド、@記号、またはハイフン以外の文字に一致します。 Word文字は、文字、10進数、またはアンダースコアなどの句読点コネクタです。このパターンに一致するすべての文字は、置換パターンで定義された文字列であるString.Emptyに置き換えられます。ユーザー入力に追加の文字を許可するには、それらの文字を正規表現パターンの文字クラスに追加します。たとえば、正規表現パターン[^\w。@-\%]では、入力文字列にパーセント記号とバックスラッシュも使用できます。
Regex.Replace(inputString, @"[!@#$%_]", "");
これも参照してください:
指定したXML文字列から文字を削除する関数は次のとおりです。
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace XMLUtils
{
class Standards
{
/// <summary>
/// Strips non-printable ascii characters
/// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
/// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0
/// </summary>
/// <param name="content">contents</param>
/// <param name="XMLVersion">XML Specification to use. Can be 1.0 or 1.1</param>
private void StripIllegalXMLChars(string tmpContents, string XMLVersion)
{
string pattern = String.Empty;
switch (XMLVersion)
{
case "1.0":
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F])";
break;
case "1.1":
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF])";
break;
default:
throw new Exception("Error: Invalid XML Version!");
}
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
if (regex.IsMatch(tmpContents))
{
tmpContents = regex.Replace(tmpContents, String.Empty);
}
tmpContents = string.Empty;
}
}
}
string XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.EncodeName(UnfilteredString);
}
string XMLReadStringWithoutIllegalCharacters(string FilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.DecodeName(UnfilteredString);
}
この簡単な方法は、無効な文字を同じ値に置き換えますが、XMLコンテキストでは受け入れられます。
文字列を書き込むには、XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)を使用します。
文字列を読み取るには、XMLReadStringWithoutIllegalCharacters(string FilteredString)を使用します。