สตริงหลบหนีเป็น XML


92

มีฟังก์ชัน C # ใดบ้างที่สามารถใช้เพื่อหลีกเลี่ยงและยกเลิกการหลีกเลี่ยงสตริงซึ่งสามารถใช้เติมเนื้อหาขององค์ประกอบ XML ได้หรือไม่

ฉันใช้ VSTS 2008 + C # + .Net 3.0

แก้ไข 1: ฉันกำลังเชื่อมไฟล์ XML ที่เรียบง่ายและสั้นเข้าด้วยกันและฉันไม่ได้ใช้การทำให้เป็นอนุกรมดังนั้นฉันจำเป็นต้องหลีกเลี่ยงอักขระ XML ด้วยมืออย่างชัดเจนตัวอย่างเช่นฉันต้องใส่a<bเข้าไป<foo></foo>ดังนั้นฉันจึงต้องใช้สตริงการหลีกเลี่ยงa<bและใส่ไว้ในองค์ประกอบ foo


ไม่ใช่วิธีเดียว แต่มีเพียงไม่กี่วิธี: http://weblogs.sqlteam.com/mladenp/archive/2008/10/21/Different-ways-how-to-escape-an-XML-string-in-C .aspx
marcc

15
สั้นที่สุดที่ฉันคิดได้:new XText(unescaped).ToString()
เห็น

3
สำหรับใครก็ตามที่สะดุดกับสิ่งนี้ฉันพบว่านี่เป็นคำตอบที่ดีที่สุด: stackoverflow.com/a/5304827/1224069
Philip Pittle

คำตอบ:


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

7
@ แต่ OP จะขอฟังก์ชันที่จะหลบหนีข้อความซึ่งสามารถใส่ไว้ในองค์ประกอบ XML ไม่ใช่แอตทริบิวต์ ฟังก์ชันของฉันไม่ได้หลีกหนีเครื่องหมายคำพูดเดี่ยวหรือคู่เพราะสามารถใส่ในองค์ประกอบ XML ได้
Darin Dimitrov

5
@darin จุดดีและอีกอย่างที่ควรเครียด ฉันพอใจกับผลลัพธ์ของการสนทนานี้และถอนการจองของฉัน ขอให้โชดดี.

1
ฉันสงสัยว่าHttpUtility.HtmlEncodeจากSystem.Webสามารถใช้ได้อย่างปลอดภัยหรือไม่?
Pooven

127

9
คำตอบนี้ใช้เครื่องหมายคำพูดไม่เหมือนกับคำตอบที่เลือก

2
คำตอบนี้ใช้ไม่ได้กับอักขระที่ไม่ถูกต้องเช่น
Haacked

16
และคุณจะหลบหนีได้อย่างไร?
Gondy

2
คำตอบนี้ไม่สมบูรณ์ มันตอบคำถามเพียงครึ่งเดียว
Brian Webster

1
เห็นด้วยกับความคิดเห็นข้างต้น - ไม่สมบูรณ์และไม่ถูกต้อง 100%
G.Stoynev

38

แก้ไข: คุณพูดว่า "ฉันกำลังเชื่อมไฟล์ XML ที่เรียบง่ายและสั้นเข้าด้วยกันและฉันไม่ได้ใช้การทำให้เป็นอนุกรมดังนั้นฉันจำเป็นต้องหลีกเลี่ยงอักขระ XML ด้วยมืออย่างชัดเจน"

ฉันขอแนะนำอย่างยิ่งว่าอย่าทำด้วยมือ ใช้ XML API เพื่อทำทุกอย่างให้คุณ - อ่านในไฟล์ต้นฉบับรวมทั้งสองไฟล์เป็นเอกสารเดียวตามที่คุณต้องการ (คุณอาจต้องการใช้XmlDocument.ImportNode) จากนั้นเขียนออกมาอีกครั้ง คุณไม่ต้องการเขียนตัวแยกวิเคราะห์ / ฟอร์แมต XML ของคุณเอง การทำให้เป็นอนุกรมไม่เกี่ยวข้องกับที่นี่

หากคุณสามารถยกตัวอย่างสั้น ๆ แต่ครบถ้วนเกี่ยวกับสิ่งที่คุณกำลังพยายามทำอยู่เราอาจช่วยให้คุณไม่ต้องกังวลกับการหลบหนีในตอนแรก


คำตอบเดิม

ยังไม่ชัดเจนว่าคุณหมายถึงอะไร แต่โดยปกติ XML API จะทำเพื่อคุณ คุณตั้งค่าข้อความในโหนดและข้อความจะหลีกเลี่ยงสิ่งที่จำเป็นโดยอัตโนมัติ ตัวอย่างเช่น:

LINQ เป็น 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; stuff & lt; & gt;" เราจะได้ผลลัพธ์ "Brackets & stuff <>"
George2

2
@ George2: คุณถาม XElement ถึงมูลค่าหรือ XmlElement สำหรับ InnerText
Jon Skeet

26

ขอบคุณ @sehe สำหรับการหลบหนีหนึ่งบรรทัด:

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

ฉันเพิ่ม un-escape บรรทัดเดียว:

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

XText ไม่หนีคำพูด
Mert Gülsoy

9

จอร์จมันเรียบง่าย ใช้ XML API เพื่อจัดการ XML เสมอ พวกเขาทำทุกวิถีทางเพื่อคุณ

อย่าสร้าง XML โดยต่อท้ายสตริง


ถ้อยทีถ้อยอาศัย มีตัวเลือก XML API มากมาย แต่สิ่งหนึ่งที่เราทุกคนควรเห็นด้วยคือการต่อสายอักขระด้วยตนเองนั้นไม่เป็นที่ยอมรับ
Steven Sudit

แม้ว่าโดยทั่วไปฉันจะเห็นด้วยกับเรื่องนี้ แต่อาจมีบางกรณีที่หายากมากที่อาจจำเป็นต้องใช้การหลบหนีด้วยตนเอง ตัวอย่างเช่นขณะสร้างเอกสาร XML โดยใช้ Roslyn
svick

@svick: ทำไมไม่สร้าง XML โดยใช้ LINQ เป็น XML แล้วใช้. ToString ()?
John Saunders

@JohnSaunders เนื่องจาก Roslyn มีชุดคลาส XML ของตัวเองเช่นXmlElementSyntax. และมันก็ซับซ้อนด้วยความจริงที่ว่าคุณต้องสร้าง///ด้วย และฉันไม่สามารถสร้างแต่ละบรรทัดแยกกันXObjectได้เพราะมันใช้ไม่ได้กับแท็กหลายบรรทัด
svick

1
@svick: สร้าง xml ทั้งหมดในบรรทัดเดียวติด///ไว้ข้างหน้าแล้วฟอร์แมตโค้ดใหม่ ไม่ใช่เรื่องใหญ่มากและแน่นอนว่าเป็นกรณีที่หักมุม หากจำเป็นจริงๆฉันแน่ใจว่าคุณสามารถสร้างแบบกำหนดเองXmlWriterเพื่อทำการแบ่งบรรทัดและเว้นวรรคในแบบที่คุณต้องการ แต่วางไว้///หน้าบรรทัดใหม่ หรือใช้ XSLT เพื่อพิมพ์ XML แบบสวย ๆ แต่ไม่ว่าในกรณีใด XML ควรสร้างขึ้นโดย XML API
John Saunders

6

และถ้าคุณต้องการเช่นฉันเมื่อฉันพบคำถามนี้เพื่อหลีกเลี่ยงชื่อโหนด XML เช่นตัวอย่างเช่นเมื่ออ่านจากการจัดลำดับ XML ให้ใช้วิธีที่ง่ายที่สุด:

XmlConvert.EncodeName(string nameToEscape)

นอกจากนี้ยังจะหลีกเลี่ยงช่องว่างและอักขระที่ไม่ถูกต้องสำหรับองค์ประกอบ XML

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


ฉันคิดว่าจากคำถามที่พวกเขาต้องการแค่ข้อความภายใน โซลูชันของคุณจะใช้งานได้ แต่ค่อนข้างจะใช้งานมากเกินไปเนื่องจากมีจุดประสงค์เพื่อจัดการกับสิ่งต่างๆเช่นชื่อองค์ประกอบและแอตทริบิวต์ \
Sean Duggan

1
ฉันมาที่นี่เพื่อพยายามหลีกเลี่ยงชื่อโหนดอะไรก็ได้และคิดว่าการค้นพบของฉันสามารถช่วยใครก็ได้ในอนาคต ฉันยังไม่เห็นว่าอะไรคือ "overkill" แต่ก็ใช้ได้ ;)
CharlieBrown

โอ้เป็นข้อมูลที่มีประโยชน์ :) ฉันเพิ่งคิดว่าฉันจะชี้ให้เห็นว่าสาเหตุหนึ่งที่คุณอาจไม่ได้รับการโหวตเพิ่มขึ้นเป็นเพราะผู้คนอาจรู้สึกว่าคุณไม่ได้ตอบคำถามในมือ
Sean Duggan

ลิงก์นี้นำไปสู่เอกสารสำหรับ SecurityElement.Escape (String) นี่เป็นเจตนาหรือไม่? XmlConvert.EncodeName (String) มีเพจของตัวเอง ฉันรู้ว่ามันถูกถามมาสองสามปีแล้ว แต่ฉันจะรู้ได้อย่างไรว่าจะใช้อันไหน? พวกเขาไม่ได้ทำสิ่งเดียวกัน แต่แตกต่างกัน?
micnil

@CharlieBrown: บางทีคุณอาจต้องการสร้างคำถามแยกต่างหากจากนั้นและตอบคำถามเพื่อให้ผู้คนค้นพบได้ดีขึ้น ขอบคุณที่โพสต์!
Florian Straub

6

อีกสิ่งหนึ่งขึ้นอยู่กับคำตอบของ John Skeet ที่ไม่ส่งคืนแท็ก :

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"

4

คำเตือน: การเนโครแมนซิ่ง

ยังคงคำตอบของ Darin Dimitrov + System.Security.SecurityElement.Escape (string s) ยังไม่สมบูรณ์

ใน XML 1.1 วิธีที่ง่ายและปลอดภัยที่สุดคือการเข้ารหัสทุกอย่าง
ชอบ&#09;สำหรับ \ t.
ไม่รองรับเลยใน XML 1.0
สำหรับ XML 1.0 วิธีแก้ปัญหาที่เป็นไปได้อย่างหนึ่งคือการเข้ารหัส 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

@Philip Pittle: ดู SpecialXmlEscape
Stefan Steiger

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.