Побег строки в XML - PullRequest
       49

Побег строки в XML

87 голосов
/ 15 июля 2009

Существует ли какая-либо функция C #, которая могла бы использоваться для экранирования и отмены экранирования строки, которая могла бы использоваться для заполнения содержимого элемента XML?

Я использую VSTS 2008 + C # + .Net 3.0.

РЕДАКТИРОВАТЬ 1: Я объединяю простые и короткие XML-файлы и не использую сериализацию, поэтому мне нужно явно экранировать XML-символ вручную, например, мне нужно поместить a<b в <foo></foo>, поэтому escape-строка a<b и поместить ее в элемент foo.

Ответы [ 10 ]

116 голосов
/ 15 июля 2009
70 голосов
/ 15 июля 2009
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;
}
36 голосов
/ 15 июля 2009

РЕДАКТИРОВАТЬ: Вы говорите: «Я конкатенирую простой и короткий файл 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. Если нет, пожалуйста, опишите подробнее.

23 голосов
/ 21 октября 2013

Спасибо @sehe за выход в одну строку:

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

Я добавляю к нему однострочный символ escape:

var unescapedAgain = System.Xml.XmlReader.Create(new StringReader("<r>" + escaped + "</r>")).ReadElementString();
8 голосов
/ 15 июля 2009

Джордж, все просто. Всегда используйте API-интерфейсы XML для обработки XML. Они делают все побеги и побеги за вас.

Никогда не создавайте XML, добавляя строки.

4 голосов
/ 29 января 2014

И если вы хотите, как я, когда я нашел этот вопрос, экранировать имена узлов XML, например, при чтении из сериализации XML, используйте самый простой способ:

XmlConvert.EncodeName(string nameToEscape)

Также будут экранированы пробелы и недопустимые символы для элементов XML.

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

3 голосов
/ 09 апреля 2014

ПРЕДУПРЕЖДЕНИЕ: Некромансирование

Тем не менее ответ Дарина Димитрова + System.Security.SecurityElement.Escape (строка s) не завершен.

В XML 1.1 самый простой и безопасный способ - просто кодировать ВСЕ.
Как &#09; для \ т.
Это совсем не поддерживается в 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);
}
2 голосов
/ 01 декабря 2018

Другой вариант, основанный на ответе Джона Скита о том, что не возвращает теги :

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"
2 голосов
/ 12 августа 2018

Использование сторонней библиотеки ( 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;"

2 голосов
/ 21 июня 2013

Следующие функции сделают работу. Не тестировал 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;
        }
    }
}
...