XMLへの文字列エスケープ


90

文字列をエスケープおよびエスケープ解除するために使用できるC#関数はありますか。XML要素のコンテンツを埋めるために使用できますか?

VSTS 2008 + C#+ .Net 3.0を使用しています。

編集1:単純な短いXMLファイルを連結しており、シリアル化を使用していないため、XML文字を手動で明示的にエスケープする必要があります。たとえば、にa<b挿入<foo></foo>する必要があるため、エスケープ文字列a<bと要素fooに挿入する必要があります。


単一の方法ではありませんが、ここにいくつかあります:http
marcc 2009

15
私が考えることができるnew XText(unescaped).ToString()
最も

3
これに
出くわした

回答:


74
public static string XmlEscape(string unescaped)
{
    XmlDocument doc = new XmlDocument();
    XmlNode node = doc.CreateElement("root");
    node.InnerText = unescaped;
    return node.InnerXml;
}

public static string XmlUnescape(string escaped)
{
    XmlDocument doc = new XmlDocument();
    XmlNode node = doc.CreateElement("root");
    node.InnerXml = escaped;
    return node.InnerText;
}

5
要素をドキュメントに追加する必要すらありません。ただし、私は最初からこれを行わないようにするのが最善だと言います。ジョージは手作業で自分のために仕事をしているようです...
Jon Skeet

15
この回答は重量が大きすぎるため、私は本当に嫌いです。XmlDocumentは実際の作業を行うためにXmlReader / XmlWriterを使用するので、追跡に切り込んでその重いDOMを避けてみませんか?
Steven Sudit、2009

7
@Willは、OPが、属性ではなくXML 要素に配置できるテキストをエスケープする関数を要求しました。私の関数は一重引用符や二重引用符をXML要素に入れることができるため、エスケープしません。
Darin Dimitrov 2010年

5
@darinの良い点、そして強調すべきです。この会話の結果に満足し、予約を取り下げます。良い一日を。

1
場合、私は疑問に思うHttpUtility.HtmlEncodeからSystem.Web安心して使用されるだろうか?
Pooven

126

8
この回答は、選択した回答とは異なり、引用符をエスケープします。

1
この回答は、 のような無効な文字では機能しないようです
Haacked

16
そして、どのようにしてエスケープを解除しますか?
ゴンディ2012

2
この答えは不完全です。質問の半分しか答えません。
ブライアンウェブスター

1
上記のコメントに同意します-不完全で100%正確ではありません。
G. Stoynev 2013

38

編集:「単純で短いXMLファイルを連結しており、シリアル化を使用していないため、手動でXML文字を明示的にエスケープする必要がある」とあなたは言う。

手で行わないことを強くお勧めします。XML APIを使用してすべてを実行します-元のファイルを読み取り、2つを1つのドキュメントにマージしますが、必要に応じて(おそらく使用する必要がありますXmlDocument.ImportNode)、それからもう一度書き出します。独自のXMLパーサー/フォーマッターを作成する必要はありません。シリアライゼーションはここでは多少関係ありません。

あなたが何をしようとしているのかを簡潔に示した完全な例を教えていただければ、そもそもエスケープについて心配する必要がないようにお手伝いできるでしょう。


元の答え

それが何を意味するのかは完全に明らかではありませんが、通常、XML APIがこれを行います。ノードにテキストを設定すると、必要なものはすべて自動的にエスケープされます。例えば:

LINQ to XMLの例:

using System;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        XElement element = new XElement("tag",
                                        "Brackets & stuff <>");

        Console.WriteLine(element);
    }
}

DOMの例:

using System;
using System.Xml;

class Test
{
    static void Main()
    {
        XmlDocument doc = new XmlDocument();
        XmlElement element = doc.CreateElement("tag");
        element.InnerText = "Brackets & stuff <>";
        Console.WriteLine(element.OuterXml);
    }
}

両方の例からの出力:

<tag>Brackets &amp; stuff &lt;&gt;</tag>

もちろん、XMLエスケープが必要な場合を想定しています。そうでない場合は、詳細を投稿してください。


ジョンに感謝します。元の投稿のEDIT 1セクションに詳細を入力しました。コメントやアドバイスをいただければ幸いです。:-)
George2

「XMLエスケープ後」-つまり?他の言葉で話していただけませんか?英語は私の母国語ではありません。:-)
George2

こんにちはジョン、XML形式から通常の文字列形式にエスケープを解除する方法、つまり入力 "ブラケット&amp;スタッフ&lt;&gt;"から、出力 "ブラケット&スタッフ<>"を取得しますか?
ジョージ2 2009

2
@ George2:XElementにその値を要求するか、XmlElementにそのInnerTextを要求します。
ジョンスキート、

25

1行のエスケープについて@seheに感謝します。

var escaped = new System.Xml.Linq.XText(unescaped).ToString();

それに1行のエスケープ解除を追加します。

var unescapedAgain = System.Xml.XmlReader.Create(new StringReader("<r>" + escaped + "</r>")).ReadElementString();

XTextは引用符をエスケープしません。
MertGülsoy、2015

9

ジョージ、それは簡単です。XMLの処理には、常にXML APIを使用してください。彼らはあなたのためにすべてのエスケープとアンエスケープを行います。

文字列を追加してXMLを作成しないでください。


生きる言葉。利用できるXML APIオプションはたくさんありますが、私たち全員が同意する必要があることの1つは、手動での文字列連結は受け入れられないということです。
Steven Sudit、2009

私はこれに概ね同意しますが、手動のエスケープが必要になる非常にまれなケースがあるかもしれません。たとえば、Roslynを使用してXMLドキュメントを作成しているとき。
スビック

@svick:LINQ to XMLを使用してXMLを作成してから、.ToString()を使用しないのはなぜですか?
ジョンサンダース

@JohnSaunders。Roslynにはのような独自のXMLクラスのセットがあるためXmlElementSyntaxです。また、生成する必要があるという事実も複雑です///。また、各行を個別のとして生成することはできませんXObject。これは、複数行タグでは機能しないためです。
スビック

1
@svick:xmlをすべて1行で生成し、その///前に貼り付けてから、コードを再フォーマットします。大したことではなく、確かに非常にまれなケースです。どうしても必要な場合XmlWriterは、改行と空白を希望どおりに作成し、///新しい行の前に配置するカスタムを作成できると思います。または、XSLTを使用してXMLをきれいに出力します。ただし、いずれの場合でも、XMLはXML APIによって生成されます。
John Saunders

5

そして、私がこの質問を見つけたときのように、たとえばXMLシリアル化から読み取るときなど、XMLノード名をエスケープするには、最も簡単な方法を使用します。

XmlConvert.EncodeName(string nameToEscape)

また、スペースやXML要素の無効な文字をエスケープします。

http://msdn.microsoft.com/en-us/library/system.security.securityelement.escape%28VS.80%29.aspx


質問に基づいて、彼らはただ内面のテキストを望んでいると思います。ソリューションは機能しますが、要素名や属性名なども処理することを目的としているため、多少やりすぎです。\
Sean Duggan

さて、私はノード名をエスケープするためにここに来て、私の発見が将来の誰かを助けることができると思いました。「やり過ぎ」とは何なのかはわかりませんが、問題ありません。;)
CharlieBrown 2014年

ああ、それは有用な情報です。:)私は、あなたが賛成されなかったかもしれない理由の1つは、あなたが目の前の質問に答えていないと人々が感じるかもしれないためだったと指摘したところです。
Sean Duggan

リンクはSecurityElement.Escape(String)のドキュメントにつながりますが、これは意図的なものでしたか?XmlConvert.EncodeName(String)には独自のページがあります。質問されてから数年になりますが、どれを使用すればよいですか?彼らは同じことをしますが、異なる方法で行いませんか?
micnil 2018

4

警告:ネクロマンシング

それでもDarin Dimitrovの回答+ System.Security.SecurityElement.Escape(string s)は完全ではありません。

XML 1.1では、最も簡単で安全な方法は、すべてをエンコードすることです。
同様に&#09;、\ tに対して。
XML 1.0ではまったくサポートされていません。
XML 1.0の場合、考えられる回避策の1つは、文字を含むテキストをbase-64エンコードすることです。

//string EncodedXml = SpecialXmlEscape("привет мир");
//Console.WriteLine(EncodedXml);
//string DecodedXml = XmlUnescape(EncodedXml);
//Console.WriteLine(DecodedXml);
public static string SpecialXmlEscape(string input)
{
    //string content = System.Xml.XmlConvert.EncodeName("\t");
    //string content = System.Security.SecurityElement.Escape("\t");
    //string strDelimiter = System.Web.HttpUtility.HtmlEncode("\t"); // XmlEscape("\t"); //XmlDecode("&#09;");
    //strDelimiter = XmlUnescape("&#59;");
    //Console.WriteLine(strDelimiter);
    //Console.WriteLine(string.Format("&#{0};", (int)';'));
    //Console.WriteLine(System.Text.Encoding.ASCII.HeaderName);
    //Console.WriteLine(System.Text.Encoding.UTF8.HeaderName);


    string strXmlText = "";

    if (string.IsNullOrEmpty(input))
        return input;


    System.Text.StringBuilder sb = new StringBuilder();

    for (int i = 0; i < input.Length; ++i)
    {
        sb.AppendFormat("&#{0};", (int)input[i]);
    }

    strXmlText = sb.ToString();
    sb.Clear();
    sb = null;

    return strXmlText;
} // End Function SpecialXmlEscape

XML 1.0:

public static string Base64Encode(string plainText)
{
    var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
    return System.Convert.ToBase64String(plainTextBytes);
}

public static string Base64Decode(string base64EncodedData)
{
    var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
    return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}

では、XML 1.1では、どのようにしてすべてをエスケープするのでしょうか。
フィリップピトル

@Philip Pittle:SpecialXmlEscapeを参照
Stefan Steiger

4

タグを返さないジョン・スキートの答えに基づく別のテイク:

void Main()
{
    XmlString("Brackets & stuff <> and \"quotes\"").Dump();
}

public string XmlString(string text)
{
    return new XElement("t", text).LastNode.ToString();
} 

これは、XMLエンコード形式で、渡された値のみを返します。

Brackets &amp; stuff &lt;&gt; and "quotes"

3

次の関数が作業を行います。XmlDocumentに対してテストしませんでしたが、これははるかに速いと思います。

public static string XmlEncode(string value)
{
    System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings 
    {
        ConformanceLevel = System.Xml.ConformanceLevel.Fragment
    };

    StringBuilder builder = new StringBuilder();

    using (var writer = System.Xml.XmlWriter.Create(builder, settings))
    {
        writer.WriteString(value);
    }

    return builder.ToString();
}

public static string XmlDecode(string xmlEncodedValue)
{
    System.Xml.XmlReaderSettings settings = new System.Xml.XmlReaderSettings
    {
        ConformanceLevel = System.Xml.ConformanceLevel.Fragment
    };

    using (var stringReader = new System.IO.StringReader(xmlEncodedValue))
    {
        using (var xmlReader = System.Xml.XmlReader.Create(stringReader, settings))
        {
            xmlReader.Read();
            return xmlReader.Value;
        }
    }
}

3

代わりにサードパーティのライブラリ(Newtonsoft.Json)を使用する:

public static string XmlEncode(string unescaped)
{
    if (unescaped == null) return null;
    return JsonConvert.SerializeObject(unescaped); ;
}

public static string XmlDecode(string escaped)
{
    if (escaped == null) return null;
    return JsonConvert.DeserializeObject(escaped, typeof(string)).ToString();
}

例:

a<b <==> "a&lt;b"

<foo></foo> <==> "foo&gt;&lt;/foo&gt;"

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.