Освобождение XML-сущностей с помощью XmlReader в .NET? - PullRequest
10 голосов
/ 14 марта 2011

Я пытаюсь удалить XML-сущности в строке в .NET (C #), но мне кажется, что она не работает правильно.

Например, если у меня есть строка AT&T, он должен быть переведен в AT&T.

Один из способов - использовать HttpUtility.HtmlDecode (), но это для HTML.

Итак, у меня есть два вопроса по этому поводу:

  1. Безопасно ли использовать HttpUtility.HtmlDecode () для декодирования объектов XML?

  2. Как мне использовать XmlReader (или что-то подобное) для этого?Я пробовал следующее, но это всегда возвращает пустую строку:

    static string ReplaceEscapes(string text)
    {
        StringReader reader = new StringReader(text);
    
        XmlReaderSettings settings = new XmlReaderSettings();
    
        settings.ConformanceLevel = ConformanceLevel.Fragment;
    
        using (XmlReader xmlReader = XmlReader.Create(reader, settings))
        {
            return xmlReader.ReadString();
        }
    }
    

Ответы [ 5 ]

14 голосов
/ 15 марта 2011

Экранирование HTML и XML тесно связаны.как вы сказали, HttpUtility имеет методы HtmlEncode и HtmlDecode.Они также будут работать с XML, поскольку есть только несколько сущностей, которые необходимо экранировать: <, >, \, ' и & в HTML и XML.

Недостатком использования HttpUtility класса является то, что вам нужна ссылка на System.Web dll, которая также содержит много других вещей, которые вам, вероятно, не нужны.

Специально для XML, *Класс 1021 *SecurityElement имеет метод Escape, который выполняет кодирование, но не имеет соответствующего метода Unescape.Поэтому у вас есть несколько вариантов:

  1. , используйте HttpUtility.HtmlDecode() и мириться со ссылкой на System.Web
  2. свернуть ваш собственный метод декодирования, который заботится оспециальные символы (так как их всего несколько - посмотрите на статический конструктор SecurityElement в Reflector, чтобы увидеть полный список)

  3. используйте (хакерское) решение, например:

.

    public static string Unescape(string text)
    {
        XmlDocument doc = new XmlDocument();
        string xml = string.Format("<dummy>{0}</dummy>", text);
        doc.LoadXml(xml);
        return doc.DocumentElement.InnerText;
    }

Лично я бы использовал HttpUtility.HtmlDecode(), если у меня уже была ссылка на System.Web, или бросил бы свою собственную, если нет.Мне не нравится ваш XmlReader подход, поскольку он Disposable, который обычно указывает на то, что он использует ресурсы, которые необходимо утилизировать, и поэтому может быть дорогостоящей операцией.

8 голосов
/ 15 марта 2011

Ваше решение № 2 может работать, но вам нужно позвонить xmlReader.Read(); (или xmlReader.MoveToContent();) до ReadString.

Я думаю, # 1 также будет приемлемым, даже если есть такиеграничные случаи, такие как &reg;, который является действительной сущностью HTML, но не сущностью XML - что должен сделать с этим ваш эскейпер?Сгенерировать исключение как правильный синтаксический анализатор XML или просто вернуть «®» так, как это сделал бы анализатор HTML?

1 голос
/ 10 марта 2016

Это также работает и имеет наименьший код:

    public static string DecodeString(string encodedString)
    {
        if (string.IsNullOrEmpty(formattedText))
            return string.Empty;
        XmlTextReader xtr = new XmlTextReader(encodedString, XmlNodeType.Element, null);
        if (xtr.Read())
            return xtr.ReadString();
        throw new Exception("Error decoding xml string : " + encodedString);
    }

Update1: хмм, кажется, он не работает, если encodeString равен "", тогда xtr.Read () возвращает false.

Обновление2: добавлен обходной путь

Update3: кажется, это работает еще лучше

    public static string DecodeString(string encodedString)
    {
        XmlTextReader xtr = new XmlTextReader(encodedString, XmlNodeType.Element, null);
        xtr.MoveToContent();
        return xtr.Value;
    }
1 голос
/ 25 мая 2012

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

Строка "Тестирование" "теряет пробел.

Если вы объедините решение в вопросе с тегом-оберткой adrianbanks, вы получите следующее, что работает.

public static string UnescapeUnicode(string line)
    {
        using (StringReader reader = new StringReader("<a>" + line + "</a>"))
        {
            using (XmlReader xmlReader = XmlReader.Create(reader))
            {
                xmlReader.MoveToContent();
                return xmlReader.ReadElementContentAsString();
            }
        }
    }
1 голос
/ 15 марта 2011

Это работает:

using (XmlReader xmlReader = XmlReader.Create(reader, settings))
{
    if (xmlReader.Read())
    {
       return xmlReader.ReadString();
    }
}
...