Thoát chuỗi sang XML


90

Có bất kỳ hàm C # nào có thể được sử dụng để thoát và bỏ thoát một chuỗi, có thể được sử dụng để điền vào nội dung của một phần tử XML không?

Tôi đang sử dụng VSTS 2008 + C # + .Net 3.0.

CHỈNH SỬA 1: Tôi đang nối tệp XML ngắn và đơn giản và tôi không sử dụng tuần tự hóa, vì vậy tôi cần phải thoát ký tự XML một cách rõ ràng bằng tay, ví dụ: tôi cần phải đưa a<bvào <foo></foo>, vì vậy tôi cần thoát chuỗi a<bvà đặt nó vào phần tử foo.


Không phải là một cách duy nhất, nhưng đây là một vài cách: http://weblogs.sqlteam.com/mladenp/archive/2008/10/21/Dierence-ways-how-to-escape-an-XML-string-in-C .aspx
marcc,

15
Ngắn nhất tôi có thể nghĩ đến:new XText(unescaped).ToString()
sehe 10/12/12

3
Đối với bất kỳ ai khác tình cờ gặp phải điều này, tôi thấy đây là câu trả lời tốt nhất: stackoverflow.com/a/5304827/1224069
Philip Pittle,

Câu trả lời:


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
Bạn thậm chí không cần phải nối phần tử vào tài liệu. Tuy nhiên, tôi vẫn muốn nói rằng nó tốt nhất là không cố gắng để làm được điều này ở nơi đầu tiên - có vẻ như George đang thực hiện công việc cho bản thân bằng cách làm mọi thứ bằng tay ...
Jon Skeet

15
Tôi thực sự không thích câu trả lời này vì nó quá nặng. XmlDocument sẽ sử dụng XmlReader / XmlWriter để thực hiện công việc thực sự, vậy tại sao không cắt theo đuổi và tránh DOM nặng nề đó?
Steven Sudit,

7
@Will, OP đã yêu cầu một hàm sẽ thoát khỏi một văn bản có thể được đặt trong một phần tử XML chứ không phải thuộc tính. Hàm của tôi không thoát khỏi dấu ngoặc kép đơn hoặc dấu ngoặc kép vì chúng có thể được đặt trong các phần tử XML.
Darin Dimitrov

5
@darin điểm tốt, và một điểm nên được nhấn mạnh. Tôi hài lòng với kết quả của cuộc trò chuyện này và rút lại yêu cầu của mình. Chúc một ngày tốt lành.

1
Tôi tự hỏi nếu HttpUtility.HtmlEncodetừ System.Webcó thể được sử dụng một cách an toàn?
Pooven

126

8
Câu trả lời này thoát khỏi dấu ngoặc kép, không giống như câu trả lời đã chọn.

1
Câu trả lời này dường như không làm việc với các nhân vật không hợp lệ như
Haacked

16
Và làm thế nào để bạn thoát khỏi?
Gondy

2
Câu trả lời này là không đầy đủ. Nó chỉ trả lời một nửa câu hỏi.
Brian Webster

1
Đồng ý với ý kiến ​​trên - không đầy đủ và không chính xác 100%.
G. Stoynev

38

CHỈNH SỬA: Bạn nói "Tôi đang nối tệp XML ngắn và đơn giản và tôi không sử dụng tuần tự hóa, vì vậy tôi cần phải thoát ký tự XML một cách rõ ràng bằng tay".

Tôi sẽ mạnh mẽ khuyên bạn không nên làm điều đó bằng tay. Sử dụng các API XML để làm tất cả cho bạn - đọc trong các tệp gốc, hợp nhất cả hai thành một tài liệu duy nhất theo cách bạn cần (có thể bạn muốn sử dụng XmlDocument.ImportNode), rồi viết lại. Bạn không muốn viết trình phân tích cú pháp / định dạng XML của riêng mình. Việc tuần tự hóa có phần không liên quan ở đây.

Nếu bạn có thể cung cấp cho chúng tôi một ví dụ ngắn gọn nhưng đầy đủ về chính xác những gì bạn đang cố gắng làm, chúng tôi có thể giúp bạn tránh phải lo lắng về việc trốn thoát ngay từ đầu.


Câu trả lời ban đầu

Nó không hoàn toàn rõ ràng bạn muốn nói gì, nhưng thông thường các API XML làm việc này cho bạn. Bạn đặt văn bản trong một nút và nó sẽ tự động thoát khỏi bất kỳ thứ gì cần thiết. Ví dụ:

Ví dụ về LINQ sang XML:

using System;
using System.Xml.Linq;

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

        Console.WriteLine(element);
    }
}

Ví dụ về 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);
    }
}

Kết quả từ cả hai ví dụ:

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

Tất nhiên là giả sử bạn muốn thoát XML. Nếu bạn không, vui lòng đăng thêm chi tiết.


Cảm ơn Jon, tôi đã đưa thêm chi tiết vào phần EDIT 1 của bài đăng ban đầu của tôi. Đánh giá cao nếu bạn có thể cho tôi một số nhận xét và lời khuyên. :-)
George 2

"sau khi thoát XML" - ý bạn là? Bạn có thể nói một số từ khác được không? Tiếng Anh không phải là ngôn ngữ mẹ đẻ của tôi. :-)
George 2

Xin chào Jon, làm cách nào để thoát khỏi định dạng XML sang định dạng chuỗi bình thường, tức là từ đầu vào "Dấu ngoặc nhọn & amp; thứ & lt; & gt;", chúng tôi nhận được đầu ra "Dấu ngoặc & thứ <>"?
George

2
@ George2: Bạn yêu cầu XElement về Giá trị của nó hoặc XmlElement về Nội dung của nó.
Jon Skeet

25

Cảm ơn @sehe vì lối thoát một dòng:

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

Tôi thêm vào nó một dòng không thoát:

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

XText không thoát khỏi dấu ngoặc kép.
Mert Gülsoy

9

George, nó đơn giản. Luôn sử dụng các API XML để xử lý XML. Họ thực hiện tất cả việc trốn thoát và bỏ trốn cho bạn.

Không bao giờ tạo XML bằng cách nối các chuỗi.


Từ để sống. Có rất nhiều tùy chọn API XML có sẵn, nhưng một điều mà tất cả chúng ta nên đồng ý là việc nối chuỗi thủ công không được chấp nhận.
Steven Sudit,

Mặc dù tôi thường đồng ý với điều này, nhưng có thể có một số trường hợp rất hiếm khi cần thoát bằng tay. Ví dụ, trong khi tạo tài liệu XML bằng Roslyn.
svick

@svick: tại sao không tạo XML bằng cách sử dụng LINQ sang XML, rồi sử dụng .ToString ()?
John Saunders

@JohnSaunders, bởi vì Roslyn có tập hợp các lớp XML của riêng mình, như XmlElementSyntax. Và nó cũng phức tạp bởi thực tế là bạn cũng cần phải tạo ra ///. Và tôi không thể tạo từng dòng riêng biệt XObject, vì điều đó sẽ không hoạt động đối với các thẻ nhiều dòng.
svick

1
@svick: vì vậy hãy tạo xml, tất cả trên một dòng, dán ///trước nó, sau đó định dạng lại mã. Không phải là một vấn đề lớn, và chắc chắn là một trường hợp góc. Nếu thực sự cần thiết, tôi chắc rằng bạn có thể tạo một tùy chỉnh XmlWriterđể thực hiện ngắt dòng và khoảng trắng theo cách bạn muốn, nhưng đặt ///trước các dòng mới. Ngoài ra, sử dụng XSLT để in XML đẹp. Nhưng trong mọi trường hợp, XML vẫn phải được tạo bởi một API XML.
John Saunders

5

Và nếu bạn muốn, giống như tôi khi tôi tìm thấy câu hỏi này, thoát khỏi các tên nút XML, chẳng hạn như khi đọc từ tuần tự hóa XML, hãy sử dụng cách dễ nhất:

XmlConvert.EncodeName(string nameToEscape)

Nó cũng sẽ thoát khỏi khoảng trắng và mọi ký tự không hợp lệ cho các phần tử XML.

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


Tôi nghĩ, dựa trên các câu hỏi, rằng họ chỉ muốn văn bản bên trong. Giải pháp của bạn sẽ làm việc, nhưng có phần hơi quá đáng vì nó dự định cũng để xử lý những thứ như tên phần tử và thuộc tính \.
Sean Duggan

Tôi đã đến đây để cố gắng thoát khỏi các tên nút bất cứ thứ gì và nghĩ rằng phát hiện của tôi có thể giúp ích cho bất kỳ ai trong tương lai. Tôi cũng không thấy "quá mức cần thiết" là gì nhưng nó ổn. ;)
CharlieBrown

Ồ, đó là thông tin hữu ích. :) Tôi chỉ nghĩ rằng tôi chỉ ra rằng một trong những lý do bạn có thể không nhận được phiếu bầu là vì mọi người có thể cảm thấy rằng bạn không trả lời câu hỏi trong tầm tay.
Sean Duggan

Liên kết dẫn đến tài liệu cho SecurityElement.Escape (String), điều này có chủ ý không? XmlConvert.EncodeName (String) có trang riêng của nó. Tôi biết nó đã được một vài năm kể từ khi được hỏi, nhưng làm thế nào để tôi biết cái nào để sử dụng? Họ không làm điều tương tự nhưng theo những cách khác nhau?
micnil

4

CẢNH BÁO: Necromancing

Vẫn là câu trả lời của Darin Dimitrov + System.Security.SecurityElement.Escape (chuỗi s) chưa hoàn thành.

Trong XML 1.1, cách đơn giản và an toàn nhất là chỉ mã hóa MỌI THỨ.
Thích &#09;cho \ t.
Nó hoàn toàn không được hỗ trợ trong XML 1.0.
Đối với XML 1.0, một giải pháp khả thi là mã hóa cơ sở 64 văn bản có chứa (các) ký tự.

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

Vậy trong XML 1.1, bạn làm cách nào để thoát khỏi mọi thứ?
Philip Pittle

@Philip Pittle: Xem SpecialXmlEscape
Stefan Steiger

4

Một cách khác dựa trên câu trả lời của John Skeet không trả về các thẻ :

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

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

Điều này chỉ trả về giá trị được truyền vào, ở định dạng được mã hóa XML:

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

3

Các chức năng sau sẽ thực hiện công việc. Không thử nghiệm với XmlDocument, nhưng tôi đoán điều này nhanh hơn nhiều.

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

Sử dụng thư viện của bên thứ ba ( Newtonsoft.Json ) để thay thế:

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

Thí dụ:

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

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.