Парсинг XML использующего namespace

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Парсинг XML использующего namespace

Сообщение Vodnik » 25.11.2022 16:13:18

Добрый день!
Имеется XML-файл такого вида (источник - система записи Verint), образец в прицепе:
Код: Выделить всё
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<x:recording xmlns:x="http://www.verint.com/xmlns/recording20080320" x:ref="472002000075371" x:version="11.2">

  <x:segment x:version="4">
    <x:complete>true</x:complete>
    <x:master>true</x:master>
    <x:keepcontent>true</x:keepcontent>
    . . .

Пробовал использовать модуль XMLConf - он такого не умеет.
Теперь пытаюсь разобрать его с помощью модулей DOM и XMLRead - в исходниках namespace встречается в изобилии, но описания и примеров найти не смог.
Первый пример отсюда http://www.freepascal.ru/article/freepascal/20080321115724 парсит XML с namespace некорректно (не находит указанные имена узлов и аттрибутов).
Помогите с базовым примером, пожалуйста!
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Vodnik
новенький
 
Сообщения: 45
Зарегистрирован: 24.12.2016 01:14:23

Re: Парсинг XML использующего namespace

Сообщение Sergei I. Gorelkin » 25.11.2022 17:51:10

По умолчанию обработка namespace не задействована, ее надо включать при чтении:
Код: Выделить всё
procedure ReadXMLFileWithNamespaces(out Doc: TXMLDocument; FileName: string);
var
  Parser: TDOMParser;
  Src: TXMLInputSource;
  InFile: TFileStream;
begin
  try
    InFile := TFileStream.Create(FileName, fmOpenRead);
    Src := TXMLInputSource.Create(InFile);
    Parser := TDOMParser.Create;
    Parser.Options.Namespaces := True;
    Parser.Parse(Src, Doc);
  finally
    Src.Free;
    Parser.Free;
    InFile.Free;
  end;
end;
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Парсинг XML использующего namespace

Сообщение Vodnik » 26.11.2022 01:06:28

Спасибо, Сергей!
Но, видимо, я чего-то не догоняю с парсингом...
Добавил Вашу процедуру в пример http://www.freepascal.ru/article/freepascal/20080321115724 (проект в прицепе, с примерами XML-файлов).
Для XML без NS работает, для XML с NS - нет.

without_ns.png

with_ns.png

Пробовал искать узел по имени с помощью FindNode - тот же результат.

Подскажите, пожалуйста, в чём ошибка?
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Vodnik
новенький
 
Сообщения: 45
Зарегистрирован: 24.12.2016 01:14:23

Re: Парсинг XML использующего namespace

Сообщение Sergei I. Gorelkin » 26.11.2022 06:54:07

Так и должно быть. При работе с namespace элементы и атрибуты определяются парой (namespaceURI, localName), а свойство NodeName возвращает localName с префиксом. Для манипуляций с DOM надо использовать методы с суффиксом NS.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Парсинг XML использующего namespace

Сообщение Vodnik » 28.11.2022 20:11:38

Спасибо за разъяснения. Стало немного проясняться.
У TDOMNode обнаружилось свойство LocalName, где имя без префикса, удобно.
Вот только почему-то нет функции FindNodeNS, аналога FindNode.
Vodnik
новенький
 
Сообщения: 45
Зарегистрирован: 24.12.2016 01:14:23

Re: Парсинг XML использующего namespace

Сообщение Vodnik » 01.02.2023 02:04:31

При парсинге любого второго файла XML возникает ошибка, первый проходит нормально.
Ошибка возникает при вызове процедуры Parser.Parse(Src, Doc);
xmlparseerror.png

Ошибка ссылается на строку 210 позицию 3 в файле с пустым именем. Не могу понять, к какому файлу она относится?
Проект с образцами файлов XML прилагается. Запускаю программу, выбираю папку "XML" и нажимаю кнопку "Scan".
Нужные файлы XML хранятся в TAR, приложение их находит и загружает в стрим. Для первого процедура парсинга (строка 280 в main.pas) проходит нормально, для второго возникает ошибка.
Дальнейший анализ приводит к процедуре TXMLTextReader.ParsePI; в модуле XMLTextReader.
Содержащийся в буфере текст 'xmlumber_of_transferses' выглядит искажённым, в тексте XML встречается 'number_of_transfers'.
ParsePI_FName.png

Пожалуйста, помогите понять, чем вызвана ошибка.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Vodnik
новенький
 
Сообщения: 45
Зарегистрирован: 24.12.2016 01:14:23

Re: Парсинг XML использующего namespace

Сообщение Sergei I. Gorelkin » 01.02.2023 03:28:34

При всех перезаписях из одного TStream в другой надо следить за их свойством Position. Скорее всего, в TarStream читается сначала один файл, нормально парсится, а затем дописывается второй и происходит попытка распарсить оба файла подряд. Содержимое буфера как бы на это намекает (там имеют значение только первые "Length" символов).
Имя файла в ошибках берется вроде бы из TXMLInputSource.BaseURI, при работе со стримами его надо присваивать самостоятельно.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Парсинг XML использующего namespace

Сообщение Vodnik » 02.02.2023 21:24:28

Всё так и оказалось, починил. Спасибо, Сергей!
Vodnik
новенький
 
Сообщения: 45
Зарегистрирован: 24.12.2016 01:14:23

Re: Парсинг XML использующего namespace

Сообщение Vodnik » 04.02.2023 23:06:23

Sergei I. Gorelkin, индикацию ошибки исправить не удалось (чтобы отображалось имя файла XML, в котором произошла ошибка). Пробовал вручную назначать имя файла в TXMLInputSource.BaseURI, не помогло.
Если работать с файлом, а не со стримом, всё равно в случае ошибки выводится пустое имя файла.
Ищу, но пока мне кажется, имя файла вообще не передаётся в парсер.
Vodnik
новенький
 
Сообщения: 45
Зарегистрирован: 24.12.2016 01:14:23


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 32

Рейтинг@Mail.ru