Подтвердить что ты не робот

Синтаксический анализ XML с помощью амперсанда

У меня есть строка, содержащая XML, я просто хочу разобрать ее в Xelement, но в ней есть амперсанд. У меня все еще есть проблема, анализирующая это с HtmlDecode. Какие-либо предложения?

string test = " <MyXML><SubXML><XmlEntry Element="test" value="wow&" /></SubXML></MyXML>"; 

XElement.Parse(HttpUtility.HtmlDecode(test));

Я также добавил эти методы для замены этих символов, но я все еще получаю XMLException.

string encodedXml = test.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;").Replace("'", "&apos;");
XElement myXML = XElement.Parse(encodedXml);

т или даже попробовал это с этим:

string newContent=  SecurityElement.Escape(test);
XElement myXML = XElement.Parse(newContent);
4b9b3361

Ответ 1

В идеале XML будет экранирован должным образом до того, как ваш код его будет использовать. Если это не под вашим контролем, вы можете написать регулярное выражение. Не используйте метод String.Replace, если вы не уверены, что значения не содержат других экранированных элементов.

Например, "wow&amp;".Replace("&", "&amp;") приводит к wow&amp;amp;, что явно нежелательно.

Regex.Replace может дать вам больше контроля, чтобы избежать этого сценария, и может быть написано только для соответствия "&" символы, которые не являются частью других символов, например &lt;, что-то вроде:

string result = Regex.Replace(test, "&(?!(amp|apos|quot|lt|gt);)", "&amp;");

Вышеупомянутое работает, но, по общему признанию, оно не охватывает множество других символов, начинающихся с амперсанда, например &nbsp;, и список может расти.

Более гибким подходом было бы декодирование содержимого атрибута value, а затем его повторное кодирование. Если у вас есть value="&wow&amp;", процесс декодирования вернет "&wow&", то повторное кодирование вернет "&amp;wow&amp;", что желательно. Чтобы снять это, вы можете использовать это:

string result = Regex.Replace(test, @"value=\""(.*?)\""", m => "value=\"" +
    HttpUtility.HtmlEncode(HttpUtility.HtmlDecode(m.Groups[1].Value)) +
    "\"");
var doc = XElement.Parse(result);

Имейте в виду, что указанное выше регулярное выражение предназначено только для содержимого атрибута value. Если в структуре XML есть другие области, которые страдают от одной и той же проблемы, тогда ее можно настроить так, чтобы она соответствовала им и заменила их содержимое аналогичным образом.


РЕДАКТИРОВАТЬ: обновленное решение, которое должно обрабатывать контент между тегами, а также что угодно между двойными кавычками. Обязательно тщательно проверьте это. Попытка манипулировать тэгами XML/HTML с регулярным выражением не является благоприятной, поскольку она может быть подвержена ошибкам и чрезмерно сложна. Ваш случай несколько особенный, так как вам нужно сначала его дезинфицировать, чтобы использовать его.
string pattern = "(?<start>>)(?<content>.+?(?<!>))(?<end><)|(?<start>\")(?<content>.+?)(?<end>\")";
string result = Regex.Replace(test, pattern, m =>
            m.Groups["start"].Value +
            HttpUtility.HtmlEncode(HttpUtility.HtmlDecode(m.Groups["content"].Value)) +
            m.Groups["end"].Value);
var doc = XElement.Parse(result);

Ответ 2

В вашей строке не содержится допустимого XML, что проблема. Вам нужно изменить строку:

<MyXML><SubXML><XmlEntry Element="test" value="wow&amp;" /></SubXML></MyXML>"

Ответ 3

HtmlEncode не будет делать трюк, он, вероятно, создаст еще больше амперсандов (например, "может стать", который является ссылкой на сущность Xml, которые следующие:

&amp;   & 
&apos;  ' 
&quot;  " 
&lt;    < 
&gt;    > 

Но вы можете получить такие вещи, как & nbsp, что хорошо в html, но не в Xml. Поэтому, как и все остальные, сначала исправьте xml, убедившись, что любой символ НЕ ЧАСТЬ ФАКТИЧЕСКОГО МАРКЕРА ВАШЕГО XML (то есть что-нибудь ВМЕСТЕ xml как переменная или текст), и который встречается в списке ссылок на сущность, переводится в соответствующий объект (так что < будет становиться <). Если текст, содержащий недопустимый символ, является текстом внутри xml node, вы можете легко и пространственно выделить текст с помощью элемента CDATA, это не будет работать для атрибутов.

Ответ 4

Амперсант делает XML недействительным. Это не может быть исправлено таблицей стилей, поэтому вам нужно написать код с помощью другого инструмента или кода в VB/С#/PHP/Delphi/ Lisp/Etc. для его удаления или для перевода на &.

Ответ 5

Если ваша строка недействительна XML, она не будет анализировать. Если он содержит амперсанд сам по себе, он недействителен XML. В отличие от HTML, XML очень строгий.

Ответ 6

Вы должны "кодировать", а не декодировать. Но вызов HttpUtility.HtmlEncode не поможет вам, поскольку он будет кодировать ваш < и ' > ', а ваша строка больше не будет XML.

Я думаю, что для этого случая лучшим решением было бы заменить '&' с '& амп;" (без пробела)

Ответ 7

Возможно, подумайте над написанием собственного XMLDocumentScanner. То, что NekoHTML делает, чтобы иметь возможность игнорировать амперсанды, не используемые в качестве ссылок на сущности.

Ответ 8

Это самый простой и лучший подход. Работает со всеми символами и позволяет анализировать XML для любого вызова веб-службы, то есть SharePoint ASMX.

public string XmlEscape(string unescaped)
        {
            XmlDocument doc = new XmlDocument();
            var node = doc.CreateElement("root");
            node.InnerText = unescaped;
            return node.InnerXml;
        }

Ответ 9

Ответ филипа находится на правильном пути, но вы можете перехватить класс System.Xml.XmlDocument, чтобы сделать это для вас без совершенно новой служебной функции.

XmlDocument doc = new XmlDocument();
string xmlEscapedString = (doc.CreateTextNode("Unescaped '&' containing string that would have broken your xml")).OuterXml;