String melarikan diri ke XML

92

Apakah ada fungsi C # yang dapat digunakan untuk keluar dan melepaskan string, yang dapat digunakan untuk mengisi konten elemen XML?

Saya menggunakan VSTS 2008 + C # + .Net 3.0.

EDIT 1: Saya concatenating sederhana dan file XML pendek dan saya tidak menggunakan serialisasi, jadi saya perlu secara eksplisit melarikan diri karakter XML dengan tangan, misalnya, saya harus menempatkan a<bke dalam <foo></foo>, jadi saya perlu melarikan diri tali a<bdan memasukkannya ke dalam elemen foo.

George2
sumber
15
Terpendek yang dapat saya pikirkan:new XText(unescaped).ToString()
lihat
3
Bagi orang lain yang tersandung pada ini, saya telah menemukan ini sebagai jawaban terbaik: stackoverflow.com/a/5304827/1224069
Philip Pittle

Jawaban:

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;
}
Darin Dimitrov
sumber
5
Anda bahkan tidak perlu menambahkan elemen ke dokumen. Namun, saya tetap akan mengatakan bahwa yang terbaik adalah tidak mencoba melakukan ini sejak awal - sepertinya George bekerja untuk dirinya sendiri dengan melakukan sesuatu dengan tangan ...
Jon Skeet
15
Saya sangat tidak menyukai jawaban ini karena terlalu berat. XmlDocument akan menggunakan XmlReader / XmlWriter untuk melakukan pekerjaan sebenarnya, jadi mengapa tidak langsung saja dan menghindari DOM yang berat itu?
Steven Sudit
7
@Apakah, OP meminta fungsi yang akan melarikan diri dari teks yang bisa dimasukkan ke dalam elemen XML dan bukan atribut. Fungsi saya tidak luput dari tanda kutip tunggal atau ganda karena dapat dimasukkan ke dalam elemen XML.
Darin Dimitrov
5
@darin bagus, dan salah satu yang harus ditekankan. Saya puas dengan hasil percakapan ini, dan menarik reservasi saya. Selamat siang, pak.
1
Saya ingin tahu apakah HttpUtility.HtmlEncodedari System.Webbisa digunakan dengan aman?
Pooven
127

SecurityElement.Escape (string s)

Dana Holt
sumber
9
Jawaban ini luput dari kutipan, tidak seperti jawaban yang dipilih.
2
Jawaban ini tampaknya tidak bekerja dengan karakter yang tidak valid seperti
Haacked
16
Dan bagaimana Anda melepaskan diri?
Gondy
2
Jawaban ini tidak lengkap. Itu hanya menjawab setengah dari pertanyaan.
Brian Webster
1
Setuju dengan komentar di atas - tidak lengkap dan tidak 100% akurat.
G. Stoynev
38

EDIT: Anda mengatakan "Saya menggabungkan file XML sederhana dan pendek dan saya tidak menggunakan serialisasi, jadi saya harus secara eksplisit melepaskan karakter XML dengan tangan".

Saya sangat menyarankan Anda untuk tidak melakukannya dengan tangan. Gunakan API XML untuk melakukan semuanya untuk Anda - baca di file asli, gabungkan keduanya menjadi satu dokumen sesuka Anda (Anda mungkin ingin menggunakannya XmlDocument.ImportNode), lalu tulis lagi. Anda tidak ingin menulis pengurai / pemformatan XML Anda sendiri. Serialisasi agak tidak relevan di sini.

Jika Anda dapat memberi kami contoh singkat namun lengkap tentang apa yang Anda coba lakukan, kami mungkin dapat membantu Anda untuk menghindari kekhawatiran tentang melarikan diri sejak awal.


Jawaban asli

Tidak sepenuhnya jelas apa yang Anda maksud, tetapi biasanya XML API melakukan ini untuk Anda. Anda mengatur teks dalam sebuah node, dan itu akan secara otomatis melarikan diri dari apapun yang diperlukan. Sebagai contoh:

Contoh LINQ ke XML:

using System;
using System.Xml.Linq;

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

        Console.WriteLine(element);
    }
}

Contoh 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);
    }
}

Keluaran dari kedua contoh:

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

Itu dengan asumsi Anda ingin XML melarikan diri, tentu saja. Jika tidak, harap posting detail selengkapnya.

Jon Skeet
sumber
Terima kasih Jon, saya telah memberikan detail lebih lanjut ke bagian EDIT 1 posting asli saya. Hargai jika Anda bisa memberi saya beberapa komentar dan nasihat. :-)
George2
"setelah XML melarikan diri" - maksud Anda? Bisakah Anda berbicara dengan kata lain? Bahasa Inggris bukan bahasa ibu saya. :-)
George2
Hai Jon, bagaimana cara melepaskan diri dari format XML ke format string normal, yaitu dari input "Brackets & amp; stuff & lt; & gt;", kami mendapatkan output "Brackets & stuff <>"?
George2
2
@ George2: Anda meminta XElement untuk Nilainya, atau XmlElement untuk InnerText-nya.
Jon Skeet
25

Terima kasih kepada @sehe untuk pelarian satu baris:

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

Saya menambahkan satu baris un-escape:

var unescapedAgain = System.Xml.XmlReader.Create(new StringReader("<r>" + escaped + "</r>")).ReadElementString();
Keith Robertson
sumber
XText tidak luput dari tanda kutip.
Mert Gülsoy
9

George, itu sederhana. Selalu gunakan API XML untuk menangani XML. Mereka melakukan semua pelarian dan pelarian untuk Anda.

Jangan pernah membuat XML dengan menambahkan string.

John Saunders
sumber
Kata-kata untuk hidup. Ada banyak opsi API XML yang tersedia, tetapi satu hal yang harus kita sepakati bersama adalah bahwa penggabungan string manual tidak dapat diterima.
Steven Sudit
Meskipun secara umum saya setuju dengan ini, mungkin ada beberapa kasus yang sangat jarang di mana pelolosan manual mungkin diperlukan. Misalnya, saat membuat dokumentasi XML menggunakan Roslyn.
svick
@svick: mengapa tidak membuat XML menggunakan LINQ ke XML, lalu gunakan .ToString ()?
John Saunders
@JohnSaunders, karena Roslyn memiliki kumpulan kelas XML-nya sendiri, seperti XmlElementSyntax. Dan itu juga diperumit oleh fakta bahwa Anda perlu membuat ///juga. Dan saya tidak dapat membuat setiap baris sebagai terpisah XObject, karena itu tidak akan berfungsi untuk tag multiline.
svick
1
@svick: jadi buat xml, semua dalam satu baris, tempelkan ///di depannya, lalu format ulang kode. Bukan masalah besar, dan tentu saja kasus sudut. Jika benar-benar diperlukan, saya yakin Anda dapat membuat kebiasaan XmlWriteruntuk melakukan jeda baris dan spasi seperti yang Anda inginkan, tetapi menempatkannya ///di depan baris baru. Atau, gunakan XSLT untuk mencetak XML dengan cantik. Namun bagaimanapun, XML tetap harus dibuat oleh API XML.
John Saunders
6

Dan jika Anda ingin, seperti saya ketika saya menemukan pertanyaan ini, untuk keluar dari nama node XML, seperti misalnya saat membaca dari serialisasi XML, gunakan cara termudah:

XmlConvert.EncodeName(string nameToEscape)

Ini juga akan mengosongkan spasi dan karakter tidak valid untuk elemen XML.

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

CharlieBrown
sumber
Menurut saya, berdasarkan pertanyaan, mereka hanya menginginkan teks batin. Solusi Anda akan berfungsi, tetapi agak berlebihan karena dimaksudkan untuk menangani hal-hal seperti nama elemen dan atribut. \
Sean Duggan
1
Saya sampai di sini mencoba untuk melarikan diri dari nama node apa pun dan berpikir bahwa temuan saya dapat membantu siapa pun di masa depan. Saya juga tidak melihat apa yang "berlebihan" tapi tidak apa-apa. ;)
CharlieBrown
Oh, itu informasi yang berguna. :) Saya baru saja menyadari bahwa saya akan menunjukkan bahwa salah satu alasan Anda mungkin tidak mendapat suara positif adalah karena orang mungkin merasa Anda tidak menjawab pertanyaan yang ada.
Sean Duggan
Tautan mengarah ke dokumen untuk SecurityElement.Escape (String), apakah ini disengaja? XmlConvert.EncodeName (String) memiliki halamannya sendiri. Saya tahu sudah beberapa tahun sejak ini ditanyakan, tetapi bagaimana saya tahu mana yang harus digunakan? Bukankah mereka melakukan hal yang sama tetapi dengan cara yang berbeda?
micnil
@CharlieBrown: Mungkin Anda juga ingin membuat pertanyaan terpisah dan menjawabnya, sehingga orang dapat menemukannya dengan lebih baik. Terima kasih telah mempostingnya!
Florian Straub
5

Pengambilan lain berdasarkan jawaban John Skeet yang tidak mengembalikan tag :

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

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

Ini hanya mengembalikan nilai yang diteruskan, dalam format yang dikodekan XML:

Brackets &amp; stuff &lt;&gt; and "quotes"
Rick Strahl
sumber
4

PERINGATAN: Necromancing

Masih jawaban Darin Dimitrov + System.Security.SecurityElement.Escape (string s) belum lengkap.

Dalam XML 1.1, cara termudah dan teraman adalah dengan menyandikan SEMUANYA.
Suka &#09;untuk \ t.
Itu tidak didukung sama sekali dalam XML 1.0.
Untuk XML 1.0, satu solusi yang mungkin adalah dengan base-64 menyandikan teks yang berisi karakter (s).

//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);
}
Stefan Steiger
sumber
Jadi di XML 1.1, bagaimana Anda bisa kabur dari semuanya?
Philip Pittle
@Philip Pittle: Lihat SpecialXmlEscape
Stefan Steiger
3

Fungsi berikut akan melakukan pekerjaannya. Tidak menguji XmlDocument, tapi saya rasa ini jauh lebih cepat.

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;
        }
    }
}
Ramazan Binarbasi
sumber
3

Menggunakan perpustakaan pihak ketiga ( Newtonsoft.Json ) sebagai alternatif:

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();
}

Contoh:

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

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

abberdeen
sumber