Исправление плохого XML-файла (например, unescaped и т. Д.)
Я получил файл XML от стороннего производителя, который я должен импортировать в свое приложение, и в XML были элементы с неэкранированным и внутренним текстом, и они не исправили это! Итак, мой вопрос: как лучше всего справиться с этой проблемой?
Этот XML довольно большой, и это исправление должно быть быстрым, мое первое решение - просто заменить & символ на амперсанд, но на самом деле мне не нравится это "решение" по понятным причинам. Я не знаю, как использовать XmlStringReader с таким XML, потому что это вызывает исключение в таких строках, поэтому я не могу использовать HtmlEncode для внутреннего текста. Я пытался установить XmlTextReader Settings.CheckCharacters
ложно, но безрезультатно.
Вот пример & в элементе, и в этом поле может быть все, что может быть в названии какой-либо компании, поэтому мое исправление замены может не работать для какого-то другого названия компании, я хотел бы как-то использовать HtmlEncode, но только на внутренний текст, конечно.
<komitent ID="001398">
<sifra>001398</sifra>
<redni_broj>001398</redni_broj>
<naziv>LJUBICA & ŽARKO</naziv>
<adresa1>Odvrtnica 27</adresa1>
<adresa2></adresa2>
<drzava>HRVATSKA</drzava>
<grad>Zagreb</grad>
</komitent>
6 ответов
Ключевое сообщение ниже состоит в том, что, если вы не знаете точный формат входного файла и не гарантируете, что любое отклонение от XML является последовательным, вы не можете программно исправить, не рискуя, что ваши исправления будут неправильными.
Исправление путем замены &
с &
является приемлемым решением, если и только если:
Не существует приемлемого, правильно сформированного источника этих данных.
- Как комментирует @Darin Dimitrov, попробуйте найти лучшего поставщика или попросите этого поставщика исправить это.
- JSON (например) предпочтительнее, чем плохо сформированный XML, даже если вы не используете JavaScript.
Это одноразовый (или, по крайней мере, крайне редкий) импорт.
- Если вам нужно получить это во время выполнения, то это решение не будет работать.
Вы можете продолжать итерацию, придумывая новые исправления для него, добавляя решение для каждой проблемы по мере ее появления.
- Вы, вероятно, обнаружите, что, как только вы "исправили" это, сбежав
&
символы, будут другие ошибки.
- Вы, вероятно, обнаружите, что, как только вы "исправили" это, сбежав
У вас есть ресурсы, чтобы вручную проверить целостность "фиксированных" данных.
- Ошибки, которые вы "исправляете", могут быть более тонкими, чем вы думаете.
В документе нет правильно отформатированных объектов -
Просто заменить
&
с&
будет ошибочно меняться"
в&quot;
, Возможно, вам удастся обойти это, но не думайте, насколько это сложно (сущности могут быть определены в DTD, могут ссылаться на кодовую точку Unicode...)Если это конкретный элемент, который плохо себя ведет, вы можете рассмотреть обертывание содержимого элемента с
<![CDATA
]]>
, но это все еще зависит от того, сможете ли вы найти начальный и конечный теги надежно.
Начните с изменения вашего мышления. Входные данные не являются XML, поэтому не называйте это XML. Даже не используйте "xml", чтобы пометить ваши вопросы об этом. Тот факт, что это не XML, означает, что вы не можете использовать какие-либо инструменты XML с ним, и вы не можете получить никаких преимуществ от обмена данными XML. Вы имеете дело с собственным форматом, который поставляется без спецификации и без каких-либо инструментов. Относитесь к нему так же, как к любому другому проприетарному формату - попробуйте найти спецификацию того, что вы получаете, и напишите для него парсер.
Если вы знаете теги файла и хотите "окей" текст внутри тегов, которые могут содержать подозрительные данные, вы можете сделать что-то вроде этого:
private static string FixBadXmlText(string xmlText)
{
var unreliableTextTags = new[] { "message", "otherdata", "stacktrace", "innerexception" };
foreach(var tag in unreliableTextTags)
{
string openTag = "<" + tag + ">";
string closeTag = "</" + tag + ">";
xmlText = xmlText.Replace(openTag, openTag + "<![CDATA[").Replace(closeTag, "]]>" + closeTag);
}
return xmlText;
}
Что-нибудь внутри раздела CDATA (<![CDATA[ {your text here} ]]>
) не будет интерпретироваться анализатором XML, поэтому его не нужно экранировать. Это помогло мне, когда мне захотелось проанализировать какой-то плохо сделанный XML, который не смог избежать выхода.
Вы можете попробовать что-то с регулярными выражениями в зависимости от сложности структуры:
Regex mainSplitter = new Regex("<komitent ID=\"([0-9]*)\">(.*?)</komitent>");
Regex nazivFinder = new Regex("<naziv>(.*?)</naziv>");
foreach (Match item in mainSplitter.Matches(test))
{
Console.WriteLine(item);
string naziv = null;
Match node = nazivFinder.Match(item.Groups[2].Value);
if (node != null)
naziv = node.Groups[1].Value;
}
Вы можете обрабатывать файл как XPL и даже использовать синтаксический анализатор XPL для преобразования таких файлов в действительный XML. XPL (расширяемый язык процессов) аналогичен XML, но анализатор допускает использование "специальных символов" XML в текстовых полях. Таким образом, вы можете запустить недопустимый XML-файл (недопустимый из-за специальных символов) через процесс XPL. В некоторых случаях вы можете использовать процессор XPL вместо процессора XML. Вы также можете использовать его для предварительной обработки неверных файлов без потери производительности. Искусственный интеллект, XML и параллелизм Java
Поскольку ваш исходный XML является ошибочным, вы не можете использовать любые XmlReaders, потому что они не могут правильно его прочитать.
Если только значения узлов XML не являются htmlEncoded, вам нужно будет вручную прочитать строку, проанализировать (получить имя узла xml и его значение), кодировать и вывести в новый файл.
Часто мы сталкиваемся с подобной ситуацией, поэтому я понимаю ваши проблемы - хотя в большинстве случаев ошибки имеют какое-то "правило", поэтому я предполагаю, что они не кодировали название компании (и, возможно, название улицы) так что вы можете просто найти эту строку <naziv>
и закрывающий тег </naziv>
и HtmlEncode все промежуточное. Кроме того, поскольку это фирменное наименование, в нем не будет разрывов строк, что может немного облегчить вашу жизнь...