Рядок переходу в XML


90

Чи існує якась функція C #, яка може бути використана для втечі та виходу з рядка, яка може бути використана для заповнення вмісту елемента XML?

Я використовую VSTS 2008 + C # + .Net 3.0.

EDIT 1: Я конкатенації простий і короткий файл XML , і я не використовую сериализации, так що мені потрібно явно уникнути XML характер вручну, наприклад, мені потрібно покласти a<bв <foo></foo>, так що мені потрібно бігти рядок a<bі помістити його в елемент взувши.



15
Найкоротше, що я можу придумати:new XText(unescaped).ToString()
sehe

3
Для тих , хто ще спотикаючись на це, я виявив , що це найкраща відповідь: stackoverflow.com/a/5304827/1224069
Філіп 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
Навіть не потрібно додавати елемент до документа. Однак я все-таки сказав би, що краще не намагатися робити це спочатку - це схоже на те, що Джордж робить собі справу, роблячи речі вручну ...
Джон Скіт

15
Мені дуже не подобається ця відповідь, оскільки вона занадто важка. XmlDocument збирається використовувати XmlReader / XmlWriter, щоб зробити справжню роботу, то чому б не відмовитись і не уникнути такої важкої DOM?
Steven Sudit

7
@Will, OP попросив функцію, яка уникає тексту, який може бути розміщений у елементі XML, а не атрибуті. Моя функція не уникає одинарних або подвійних лапок, оскільки їх можна помістити в елементи XML.
Дарін Димитров

5
@darin хороший момент, і той, на якому слід наголосити. Я задоволений результатом цієї розмови і відкликаю свої застереження. Доброго дня, сер.

1
Цікаво , якщо HttpUtility.HtmlEncodeз System.Webможна безпечно використовувати?
Пувен

126

8
Ця відповідь уникає лапок, на відміну від вибраної відповіді.

1
Здається, ця відповідь не працює з недійсними символами, такими як
Злом

16
А як ти втечеш?
Гонді,

2
Ця відповідь неповна. Це відповідає лише на половину запитання.
Брайан Вебстер,

1
Погодьтесь із наведеними вище коментарями - неповними та не на 100% точними.
Г. Стойнєв

38

EDIT: Ви говорите: "Я об'єдную простий і короткий XML-файл, і я не використовую серіалізацію, тому мені потрібно явно уникати символу XML вручну".

Я настійно радив би вам не робити це вручну. Використовуйте API XML, щоб зробити все за вас - прочитайте оригінальні файли, об’єднайте два в один документ, як вам потрібно (ви, мабуть, хочете використовуватиXmlDocument.ImportNode ), а потім випишіть його знову. Ви не хочете писати власні аналізатори / форматування XML. Серіалізація тут дещо неактуальна.

Якщо ви можете дати нам короткий, але повний приклад того, що саме ви намагаєтесь зробити, ми, ймовірно, можемо допомогти вам уникнути необхідності турбуватися про втечу.


Оригінальна відповідь

Не зовсім зрозуміло, що ви маєте на увазі, але зазвичай API XML робить це за вас. Ви встановлюєте текст у вузлі, і він автоматично уникне всього, що йому потрібно. Наприклад:

Приклад 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;", ми отримаємо вихід "Дужки & речі <>"?
George2

2
@ George2: Ви запитуєте у XElement його значення або у XmlElement його InnerText.
Джон Скіт,

25

Дякую @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: чому б не створити XML, використовуючи LINQ to XML, а потім використовувати .ToString ()?
Джон Сондерс,

@JohnSaunders, оскільки Roslyn має власний набір класів XML, наприклад XmlElementSyntax. І це ускладнюється ще й тим, що вам теж потрібно генерувати ///. І я не можу генерувати кожен рядок як окремий XObject, оскільки це не буде працювати для багаторядкових тегів.
свик

1
@svick: отже, згенеруйте xml, все в одному рядку, тримайтеся ///перед ним, а потім переформатуйте код. Не дуже велика справа, і, звичайно, дуже велика справа. У разі крайньої необхідності я впевнений, що ви можете створити спеціальний XmlWriterрозрив рядків та пробіли так, як вам заманеться, але розміщення ///перед новими рядками. Крім того, використовуйте XSLT для симпатичного друку XML. Але в будь-якому випадку XML все одно повинен генеруватися XML API.
Джон Сондерс,

5

І якщо ви хочете, як я, коли я знайшов це запитання, уникнути імен вузлів XML, як, наприклад, під час читання з серіалізації XML, використовуйте найпростіший спосіб:

XmlConvert.EncodeName(string nameToEscape)

Він також уникне пробілів та будь-яких неприпустимих символів для елементів XML.

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


Я думаю, виходячи з питань, що вони просто хочуть внутрішній текст. Ваше рішення спрацює, але дещо надмірно, оскільки воно також призначене для обробки таких речей, як імена елементів та атрибутів. \
Шон Дагган,

Ну, я потрапив сюди, намагаючись уникнути імен вузлів, і думав, що мої результати можуть допомогти будь-кому в майбутньому. Я також не бачу, що таке "надмірне", але це нормально. ;)
CharlieBrown

О, це корисна інформація. :) Я просто припустив, що зазначу, що однією з причин, за якою ви могли б не проголосувати, було те, що люди могли відчути, що ви не відповідаєте на поставлене запитання.
Шон Дагган,

Посилання веде до документів для SecurityElement.Escape (String), чи було це навмисно? XmlConvert.EncodeName (рядок) має власну сторінку. Я знаю, що минуло кілька років з того моменту, як це запитали, але як я знаю, який із них використовувати? Чи не вони роблять одне і те ж, але по-різному?
micnil

4

ПОПЕРЕДЖЕННЯ: Некромантування

Все-таки відповідь Даріна Димитрова + System.Security.SecurityElement.Escape (рядок) не є повною.

У 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: Див. 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;"

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.