Как предотвратить System.Xml.XmlException: недопустимый символ в заданной кодировке
У меня есть настольное приложение для Windows, написанное на C#, которое просматривает кучу XML-файлов, хранящихся на диске и созданных сторонней программой. Большинство файлов загружаются и успешно обрабатываются кодом LINQ, следующим за этим утверждением:
XDocument xmlDoc = XDocument.Load(inFileName);
List<DocMetaData> docList =
(from d in xmlDoc.Descendants("DOCUMENT")
select new DocMetaData
{
File = d.Element("FILE").SafeGetAttributeValue("filename")
,
Folder = d.Element("FOLDER").SafeGetAttributeValue("name")
,
ItemID = d.Elements("INDEX")
.Where(i => (string)i.Attribute("name") == "Item ID(idmId)")
.Select(i => (string)i.Attribute("value"))
.FirstOrDefault()
,
Comment = d.Elements("INDEX")
.Where(i => (string)i.Attribute("name") == "Comment(idmComment)")
.Select(i => (string)i.Attribute("value"))
.FirstOrDefault()
,
Title = d.Elements("INDEX")
.Where(i => (string)i.Attribute("name") == "Title(idmName)")
.Select(i => (string)i.Attribute("value"))
.FirstOrDefault()
,
DocClass = d.Elements("INDEX")
.Where(i => (string)i.Attribute("name") == "Document Class(idmDocType)")
.Select(i => (string)i.Attribute("value"))
.FirstOrDefault()
}
).ToList<DocMetaData>();
... где inFileName - полный путь и имя файла, например:
Y:\S2Out\B0000004\Pet Tab\convert.B0000004.Pet Tab.xml
Но некоторые файлы вызывают такие проблемы:
System.Xml.XmlException: Invalid character in the given encoding. Line 52327, position 126.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.InvalidCharRecovery(Int32& bytesCount, Int32& charsCount)
at System.Xml.XmlTextReaderImpl.GetChars(Int32 maxCharsCount)
at System.Xml.XmlTextReaderImpl.ReadData()
at System.Xml.XmlTextReaderImpl.ParseAttributeValueSlow(Int32 curPos, Char quoteChar, NodeData attr)
at System.Xml.XmlTextReaderImpl.ParseAttributes()
at System.Xml.XmlTextReaderImpl.ParseElement()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r)
at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r, LoadOptions o)
at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)
at System.Xml.Linq.XDocument.Load(String uri, LoadOptions options)
at System.Xml.Linq.XDocument.Load(String uri)
at CBMI.WinFormsUI.GridForm.processFile(StreamWriter oWriter, String inFileName, Int32 XMLfileNumber) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 147
at CBMI.WinFormsUI.GridForm.btnProcess_Click(Object sender, EventArgs e) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 105
Файлы XML выглядят так (в этом примере показаны только 2 элемента DOCUMENT, но их много):
<?xml version="1.0" ?>
<DOCUMENTCOLLECTION>
<DOCUMENT>
<FILE filename="e:\S2Out\B0000005\General\D003712420.0001.pdf" outputpath="e:\S2Out\B0000005\General"/>
<ANNOTATION filename=""/>
<INDEX name="Comment(idmComment)" value=""/>
<INDEX name="Document Class(idmDocType)" value="General"/>
<INDEX name="Item ID(idmId)" value="003712420"/>
<INDEX name="Original File Name(idmDocOriginalFile)" value="Matrix Aligning 603.24 Criteria to Petition Pages.pdf"/>
<INDEX name="Title(idmName)" value="Matrix for 603.24"/>
<FOLDER name="/Accreditation/PASBVE/2004-06"/>
</DOCUMENT>
<DOCUMENT>
<FILE filename="e:\S2Out\B0000005\General\D003712442.0001.pdf" outputpath="e:\S2Out\B0000005\General"/>
<ANNOTATION filename=""/>
<INDEX name="Comment(idmComment)" value=""/>
<INDEX name="Document Class(idmDocType)" value="General"/>
<INDEX name="Item ID(idmId)" value="003712442"/>
<INDEX name="Original File Name(idmDocOriginalFile)" value="Contacts at NDU.pdf"/>
<INDEX name="Title(idmName)" value="Contacts at NDU"/>
<FOLDER name="/Accreditation/NDU/2006-12/Self-Study"/>
</DOCUMENT>
У операторов LINQ есть свои сложности, но я думаю, что это работает нормально; это НАГРУЗКА, которая терпит неудачу. Я посмотрел на различные конструкторы для XDocument Load и исследовал некоторые другие вопросы, связанные с этим исключением, но я не понимаю, как это предотвратить.
Наконец, в строке 52327, позиция 126, в файле, который не удалось загрузить, кажется, что эти данные в строке 52327 НЕ должны были вызвать проблему (а последний символ находится в позиции 103!
<FILE filename="e:\S2Out\B0000004\Pet Tab\D003710954.0001.pdf" outputpath="e:\S2Out\B0000004\Pet Tab"/>
4 ответа
Чтобы контролировать кодировку (когда вы знаете, что это такое), вы можете загрузить файлы, используя Load
переопределение метода, который принимает Stream
,
Тогда вы можете создать новый StreamReader
против вашего файла с указанием соответствующего Encoding
в конструкторе.
Например, чтобы открыть файл с использованием западноевропейской кодировки, замените следующую строку кода в вопросе:
XDocument xmlDoc = XDocument.Load(inFileName);
с этим кодом:
XDocument xmlDoc = null;
using (StreamReader oReader = new StreamReader(inFileName, Encoding.GetEncoding("ISO-8859-1"))) {
xmlDoc = XDocument.Load(oReader);
}
Список поддерживаемых кодировок можно найти в документации MSDN.
Поскольку XmlDocument загружает все, как только он переходит в незашифрованный символ, он прерывает весь процесс. Если вы хотите обработать то, что можете, и пропустить / записать ненужные биты, посмотрите на XmlTextReader. XmlTextReader, загруженный из Filestream, будет загружать узел за раз, поэтому он также будет использовать намного меньше памяти. Вы можете даже стать умнее, разбить вещь и распараллелить обработку.
Когда у меня было это, там были такие вещи, как акцентированные персонажи: могила, острый, умлаут и тому подобное.
У меня нет никаких автоматизированных процессов, поэтому обычно я просто загружаю файл в Visual Studio и редактирую плохих парней до тех пор, пока не останется скандалов. Теория обоснована, хотя.
Указанный файл содержит символ, допустимый для имени файла, но недопустимый в атрибуте XML. У вас есть несколько вариантов.
- Вы можете изменить имя файла и перезапустить свой сторонний скрипт.
- Вы могли бы работать с поставщиком, чтобы обеспечить исправление, которое безопасно кодирует оскорбительные символы.
- Вы можете предварительно проверить документы XML и удалить ошибочные записи перед обработкой.
Не уверен, что это ваш случай, но это может быть связано с недопустимыми байтовыми последовательностями для данной кодировки. Пример: http://en.wikipedia.org/wiki/UTF-8.
Попробуйте отфильтровать неверные последовательности из файла во время загрузки.