Сергей П.
37 сообщений
#16 лет назад
Привет всем, помогите пожалуйста с проверкой на валидность XML-файла (на php).

Сейчас существует обработка приема информации из XML-файлов (объемы где-то максимум до гигабайта) через XMLReader и DOM с подключение RNG схемы. Всё работает супер, пока не всречается первая ошибка по некорректности XML-структуры.


Структура XML такого вида:

<?xml version="1.0" encoding="windows-1251"?>
<files version="2.0">
<info recnumber="1">
...
</info>

...

<info recnumber="n">
...
</info>
</files>


Проблематика в том, при возникновении ошибок, прием информации из файла останавливается (строит проверка на возврат валидности), а надо продолжать, убирать схему для проверки не хочется, т.к. многие ошибки вылавливаются именно по схеме.

Есть замысел сделать две схемы, одну облегченную, на весь файл, а вторую на блок info, чтобы если не коректен именно блок, то делать пропуск блока (без его принятия в систему) и идти дальше к другому блоку. Но не могу понять как реализовать програмную часть, т.е. поставить схему именно для проверки блока info. В инете ничего похожего не нашел, хотя может и плохо искал.

помогите какими-нибудь мыслями...
Вадим Т.
3240 сообщений
#16 лет назад
> Сейчас существует обработка приема информации из XML-файлов (объемы где-то максимум до гигабайта) через XMLReader и DOM

programmist, Вы шутите? Какой DOM на таких объемах??? Да уже на XML файле размером несколько мегабайт DOM парсер сдохнет и вывалится по превышению лимита памяти PHP. SAX парсер нужно использовать, SAX, SAX и ничего кроме SAX. В принципе можете использовать мой Open Source класс для этих целей, скорее всего поможет:

Далее, про валидность. Суть проверки валидности XML в том, что если хоть что-то в XML документе не валидно, то весь документ считать невалидным. Так и должно быть. "Частичной валидности" тут быть не может, по спецификации. Если же Вам это нужно то что же... используйте свой собственный парсер на регекспах, но я это не рекомендую делать.

Повторюсь, лучшее решение - используйте родной SAX парсер PHP, например, в либе моей реализации, это будет работать очень быстро и почти не отжирая оперативную память, и будет принимать и обрабатывать данные до конца файла любого размера или до первой ошибки (в отличии от DOM, которые вообще не будет работать в случае хоть какой-то ошибки). Потом, в случае ошибки валидности XML, парсер остановится, и выкинет Exception, Вы этот Exception сможете перехватить, и продолжать работать с уже полученными данными.
Сергей П.
37 сообщений
#16 лет назад
Цитата:
programmist, Вы шутите? Какой DOM на таких объемах??? Да уже на XML файле размером несколько мегабайт DOM парсер сдохнет и вывалится по превышению лимита памяти PHP. SAX парсер нужно использовать, SAX, SAX и ничего кроме SAX. В принципе можете использовать мой Open Source класс для этих целей, скорее всего поможет: ]https://www.weblancer.net/users/tvv/portfolio/147889.html


Я же написал, XMLReader с DOM. А SAX не подходит по параметрам задачи, из-за этого и не использую. И кстати XMLReader работает не хуже Сакса.

Цитата:
Далее, про валидность. Суть проверки валидности XML в том, что если хоть что-то в XML документе не валидно, то весь документ считать невалидным. Так и должно быть. "Частичной валидности" тут быть не может, по спецификации. Если же Вам это нужно то что же... используйте свой собственный парсер на регекспах, но я это не рекомендую делать.

Повторюсь, лучшее решение - используйте родной SAX парсер PHP, например, в либе моей реализации, это будет работать очень быстро и почти не отжирая оперативную память, и будет принимать и обрабатывать данные до конца файла любого размера или до первой ошибки (в отличии от DOM, которые вообще не будет работать в случае хоть какой-то ошибки). Потом, в случае ошибки валидности XML, парсер остановится, и выкинет Exception, Вы этот Exception сможете перехватить, и продолжать работать с уже полученными данными.


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

Вроде бы нашел решение все с теми же XMLReader и DOM'ом, но есть некоторые нюансы... попробуем побороться
Вадим Т.
3240 сообщений
#16 лет назад
В принципе, для Вашего случая можно сделать свой парсер, хоть и не универсальный, заточенный под Ваш конкретный XML документ. Например, на регекспах. Работать будет быстрее всего, и именно так, как Вы хотите, не вылетая при ошибках. Это решение, конечно, не элегантное, и идеологически неправильное, но работать будет так как Вам нужно на данном документе.

P.S. XMLReader конечно же не хуже SAX, для своего круга задач. На простой линейной выборке сам по себе XMLReader без DOM работает немного быстрее чем SAX, за счет отсутствия колбеков. Но вот использовать его не очень удобно. Поэтому Вы например используете дополнительно DOM. А вот DOM для таких задач, на таких объемах информации, использовать кощунственно, пусть и только для узлов, которые возвращает быстрый XMLReader. Проверить это несложно. Просто сделайте несколько примеров с разными вариантами парсеров, проведите замеры по времени - сразу увидите разницу.

То есть, если Вы и используете XMLReader, то делайте это хотя бы без DOM (без XMLReader::expand)... Кстати, XMLReader можно использовать только начиная с PHP 5.1, так что это учитывайте при выборе хостинга.
Сергей П.
37 сообщений
#16 лет назад
Как раз метод, который я нашел, делается через expand для создания DOMNode, а из него и DOMDocument, к которому после можно подцепить схему для поверки. а сервер у нас свой...
Сергей П.
37 сообщений
#16 лет назад
<?xml version="1.0" encoding="windows-1251"?>
<files version="2.0">
<info recnumber="1">
...
</info>

...

<info recnumber="n">
...
</info>
</files>


возможно ли написать схему, которая не проверяет структуру блока info, а проверяет только наличие начала блока и конец блока, т.е. элемент info сделать как бы неопределенного типа.
P.S.: не надо показывать спецификации документов, я это всё знаю, просто хочу спросить, существует ли такой метов построения XSD (RNG) схем?
Сергей П.
37 сообщений
#16 лет назад
Ой всё сделал
Вадим Т.
3240 сообщений
#16 лет назад
programmist, кстати, спасибо что натолкнули на идею с XMLRеader-ом... В свою Open Source либу MultiXML вставил код:

        if (class_exists('XMLReader')) {
$this->parse_xmlreader($fname);
} else {
$this->parse_sax($fname);
}

При этом, конечно, написав метод parse_xmlreader, без использования DOM. Как я и предполагал теоретически, если запускать из PHP 5.1 и выше, либа теперь работает примерно на 10-15% быстрее, за счет более низкоуровневого парсинга и отсутствия колбеков. Только что проверил на нескольких XML с разной структурой и размером до 100 Mb. Еще погоняю, и скоро обновлю версию.
Сергей П.
37 сообщений
#16 лет назад
Да я тоже бы через DOM не делал, но там стоит такая задача, что надо использовать