gifts2017

Вычисление и отладка выражений XPath

Опубликовал Андрей Овсянкин (Evil Beaver) в раздел Администрирование - Сервисные утилиты

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

Поводом к написанию обработки стала необходимость отладить выражение XPath, которое должно было вычисляться относительно узла, расположенного где-то в середине большого файла. К моему удивлению, адекватных бесплатных средств работы с XML, которые бы позволили это сделать - нет.

Все те утилиты, которые удалось найти делали это либо плохо, либо не так, как надо. Нужный функционал был в платном пакете XML Spy, однако, даже там нужно было писать весь путь от начала документа. Мне же нужно было проверить выражение относительно середины документа....Frown

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

  • Быстро и просто подготовить отладку выражения - вставить XML текст, ввести выражение, выполнить.
  • Отображает результат выражения в виде дерева узлов. Все узлы, попавшие в результат выражения визуализируются.
  • Позволяет узнать текущий путь в документе для любого узла. То есть, для любого узла можем получить его путь в виде "/parent/parent[2]/child[3]"
  • Позволяет вычислять выражение относительно произвольного контекста. Например, есть длинный документ, в середине которого есть узел, на котором вам нужно вычислить выражение. Порядок действий:
  • 1. Вычисляем выражение "/" и получаем визуальное дерево документа (выполнять п.1 необязательно, можно писать сразу выражение)
  • 2. Переходим в дереве на нужный узел и устанавливаем его в качестве текущего
  • 3. Пишем выражение относительно текущего узла, а не от корня документа, как в большинстве аналогов
  • 4. Наслаждаемся

При просмотре дерева используется динамический выбор узлов DOM, т.е. дерево результата не строится целиком, а экономит память и отображает узлы по мере необходимости.

Скачать файлы

Наименование Файл Версия Размер
Обработка вычисления выражений XPath 112
.epf 11,29Kb
30.10.12
112
.epf 11,29Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. kiril lipatov (kilokilo) 31.10.12 03:38
2. Герман (German) 31.10.12 08:53
Я XMLSрy использую, но + за стремление
3. Алексей Штепа (unknownDaemon) 18.11.12 14:52
Люто плюсанул :) Но позволил себе наглость чуть-чуть добавить функционала :) Скрин и результат прилагаю…
Теперь можно и имеет смысл юзать почти все что угодно из вот этого набора например…

То есть, результат такой конструкции: ceiling(sum(//Товары//Сумма)) max(//Товары//Количество) можно увидеть в соответсвующем поле при выборе ТипРезультата=ТипРезультатаDOMXPath.Число … ну и с остальными вариантами также ;-)

ЗЫ Еще раз спасибо за проделанный труд!
Прикрепленные файлы:
ОтладкаXPath.epf
4. Алексей Штепа (unknownDaemon) 18.11.12 14:58
(2) German, XMLSpy оно ж не одинэсовское вроде? Просто какбэ реализации 1С разновсяческих API весьма своеобразное… Наталкивался на непонимания ряда функций и чудеса синтаксиса… Так-что лучше отладку делать нативно ;-)

ЗЫ Еще бы регэкспы добавили нативно внутря — цены бы платформк не было ;-)
5. Евгений Шабалин (xzorkiix) 12.07.13 10:45
(0) у меня вопрос это проблема реализации xpath в 1С, или ЧЯДНТ?

Пытаюсь выбрать все элементы Acceptance для которых подчиненный элемент имеет необходимый текст (значение).

xpath выражение не отрабатывает в обработке (8.2)


но работает в другом инструменте корректно (notepad++)


UPD: Запрос /soap:Envelope[soap:Header="test"] работает. Скорее всего что-то связано с namespace атрибутов.
6. Андрей Овсянкин (Evil Beaver) 12.07.13 11:10
(5) xzorkiix, из скриншотов не видно - на что маппится префикс "m:". Соответствие префиксов и URI настраивается на второй закладке. Возможно, notepad++ умеет это делать сам.
7. Евгений Шабалин (xzorkiix) 12.07.13 11:19
(6) я выше подправил, вижу что для soap: который по умолчанию занесен в файл всё ок.

Все возможные ns в xml

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>test</soap:Header>
<soap:Body> <m:GetAcceptanceListResponse xmlns:m="urn:wss2/1SESL/1.0">
<m:return xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Acceptance xmlns="urn:wss2/Integration/1.0">

Попробовал и вторую вкладку раскидать, но видимо ещё мимо. Не нужно ли здесь использовать Фабрику XDTO? (как в случае сервиса)

8. Андрей Овсянкин (Evil Beaver) 12.07.13 11:26
(7) xzorkiix, нет, фабрика не нужна. Если дадите сам файл и искомое выражение, могу посмотреть, но вечером.
аааа... стоп-стоп... похоже понял

У вас "пустой" префикс задан для пространства по умолчанию. в XPath по стандарту пустые префиксы не прокатывают. Назовите его как-нибудь, скажем "t" и все узлы "без префиксов" в выражении адресуйте, как "t:"
9. Евгений Шабалин (xzorkiix) 12.07.13 11:57
(8) Пустое, это уже была попытка угадать. Под фабрикой я понимал Пакет XDTO (это тоже была попытка угадать). Буду смотреть файл, если будут вопросы - побеспокою. А в целом ваше предположение мне кажется верным (о том что необходимо присвоить префикс всем вхождениям, где я произвожу поиск).

Спасибо.
10. Андрей Овсянкин (Evil Beaver) 12.07.13 13:01
(9) xzorkiix, это не просто предположение, а уже набитая шишка. Пустые префиксы не канают и это не глюк, а фича XPath.
11. Евгений Шабалин (xzorkiix) 12.07.13 14:57
(10) Перебрал имеющуюся строку XML с принудительной расстановкой префиксов ns в имени элементов. Взлетело.



Префиксы = Новый Соответствие;

ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("UTF-8");

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстовыйДокумент.ПолучитьТекст());
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла=ТипУзлаXML.НачалоЭлемента Тогда

Префикс = Префиксы.Получить(ЧтениеXML.URIПространстваИмен);
Если Префикс = Неопределено Тогда
Префикс = "myns" + Формат(Префиксы.Количество()+1,"ЧГ=");
Префиксы.Вставить(ЧтениеXML.URIПространстваИмен, Префикс);
конецЕсли;

ЗаписьXML.ЗаписатьНачалоЭлемента(Префикс + ":" + ЧтениеXML.ЛокальноеИмя);
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен(Префикс, ЧтениеXML.URIПространстваИмен);

ИначеЕсли ЧтениеXML.ТипУзла=ТипУзлаXML.Текст Тогда
ЗаписьXML.ЗаписатьТекст(ЧтениеXML.Значение);
ИначеЕсли ЧтениеXML.ТипУзла=ТипУзлаXML.КонецЭлемента Тогда
ЗаписьXML.ЗаписатьКонецЭлемента();
ИначеЕсли ЧтениеXML.ТипУзла=ТипУзлаXML.ОбъявлениеXML Тогда
ЗаписьXML.ЗаписатьОбъявлениеXML();
КонецЕсли;
КонецЦикла;

Сообщить(ЗаписьXML.Закрыть());


PS Закладку с ns не трогал, как есть

12. Андрей Овсянкин (Evil Beaver) 12.07.13 16:34
(11) xzorkiix, нужно было наоборот.
1. Исходный текст имеет пространство по-умолчанию, скажем, Х (икс), и все узлы записаны без префиксов
2. На закладке пространства имен для Х указываем некий произвольный префикс, скажем, х(икс).
3. В выражении XPath обращаемся к узлам, которые без префиксов, через префикс х(икс), указанный на закладке
4. PROFIT. исходный XML не модифицируем, он идет, как есть.

т.е. у вас в файле <Узел>, а в выражении - x:Узел
13. Евгений Шабалин (xzorkiix) 18.07.13 11:39
(12)[посыпает голову пеплом]. Спасибо.
14. Сергей Ожерельев (Поручик) 04.09.13 15:57
(5) Для notepad++ какой-то плагин? В самом редакторе на нашёл, в XML Tools тоже нет похожего.
15. Андрей Овсянкин (Evil Beaver) 04.09.13 19:58
(14) Поручик, тоже не вижу плагина...
16. Сергей Ожерельев (Поручик) 04.09.13 20:52
(15) Нашёл. xpatherizernpp. XML XPath Query Analyzer Plugin for NotePad ++. https://code.google.com/p/xpatherizernpp/
17. Сергей Ожерельев (Поручик) 05.09.13 00:00
(15) Ещё до кучи в качестве закладки
XPather
...generates XPaths while browsing or inspecting HTML/XML/*ML documents; evaluates your XPaths and inspects the results; extracts the content.
http://xpath.alephzarro.com/
18. Андрей Овсянкин (Evil Beaver) 05.09.13 09:37
(17) Поручик, не ставил пока, спрошу: а они умеют вычислять не относительно начала документа, а относительно произольного узла?
19. Сергей Ожерельев (Поручик) 05.09.13 11:04
(18) В плагине для notepad++ понятия произвольного узла нет. И другой момент, если для документа установлена кодировка UTF-XX, то он плохо работает с кириллическими названиями тэгов, атрибутов, текстовым содержимым. Надо переключаться в режим ANSI.
20. Андрей Овсянкин (Evil Beaver) 09.09.13 20:38
(19) Поручик, тогда фтопку плагин, моя обработка рулит! ;)
21. Сергей Ожерельев (Поручик) 09.09.13 20:48
(20) Я пользуюсь обеими средствами. У тебя не сохраняется сам текст xml и нет возможности загрузить из файла. Могу и сам сделать, но лень. Зато в плагине не сохраняется выражение Xpath. Кстати, рекомендую сохранять историю выражений в списке выбора.
Я бы сделал, но ту свою задачу выполнил и уже особо не интересно.
Evil Beaver; +1 Ответить 1
22. Евгений Шабалин (xzorkiix) 24.10.13 14:51
(12)Evil Beaver,

Вернулся к XPath, прибег к рекомендации из (12). Всё так и есть.

Может кому будет полезно

На примере
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0">
<Schema Namespace="Microsoft.SharePoint.DataService" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">
<EntityType Name="AttachmentsItem" m:HasStream="true">
<Key>
<PropertyRef Name="EntitySet" />
<PropertyRef Name="ItemId" />
<PropertyRef Name="Name" />
</Key>
<Property Name="EntitySet" Type="Edm.String" Nullable="false" />
<Property Name="ItemId" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" Nullable="false" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="true" />
</EntityType>
</Schema>
</edmx:DataServices>
</edmx:Edmx>


Поиск через выражение /edmx:Edmx/edmx:DataServices[1]/Schema[1]/EntityType[1] не даёт ожидаемого результата (результат пустой).

Добавляем на вкладке "Соответствие.." пару
Префикс emn URI http://schemas.microsoft.com/ado/2007/05/edm

Выражение корректируем, как /edmx:Edmx/edmx:DataServices[1]/edm:Schema[1]/edm:EntityType[1]

Получаем в ответе - требуемый узел. PROFIT

Немного подправил функцию ВычислитьПредставлениеТекущегоПути при формировании пути не было требуемых префиксов (из таблицы "Соответствия.."). В моем случае работает корректно

Функция ВычислитьПредставлениеТекущегоПути(Знач ТекущийУзел)

// <-- xzorkiix
#Если НЕ (Клиент Или Сервер Или ВнешнееСоединение) Тогда
DOM = Новый ДокументDOM();
ТекущийУзел = DOM.ЭлементДокумента; // ЭлементDOM (DOMElement)
#КонецЕсли
// -->

Если ТекущийУзел.РодительскийУзел <> Неопределено Тогда

Если ТекущийУзел.ТипУзла = ТипУзлаDOM.Элемент Тогда
Если ТекущийУзел = мДокументDOM.ЭлементДокумента Тогда
ИмяУзла = ТекущийУзел.ИмяУзла;
Иначе

СчетчикСоседей = 0;
СоседнийУзел = ТекущийУзел.ПредыдущийСоседний;
Пока СоседнийУзел <> Неопределено Цикл
СчетчикСоседей = СчетчикСоседей + 1;
СоседнийУзел = СоседнийУзел.ПредыдущийСоседний;
КонецЦикла;

ИмяУзла = ТекущийУзел.ИмяУзла + "[" + (СчетчикСоседей+1) + "]";

КонецЕсли;
ИначеЕсли ТекущийУзел.ТипУзла = ТипУзлаDOM.Текст Тогда
ИмяУзла = "text()";
Иначе
ИмяУзла = ТекущийУзел.ИмяУзла;
КонецЕсли;

// <-- xzorkiix
// Подберем префикс из СоответствияПространствИмен
Если ПустаяСтрока(ТекущийУзел.Префикс) Тогда

ЗаписьСоответствияПространствИмен = СоответствияПространствИмен.Найти(
ТекущийУзел.URIПространстваИмен, "ПространствоИмен");

Если ЗаписьСоответствияПространствИмен <> Неопределено
И Не ПустаяСтрока(ЗаписьСоответствияПространствИмен.Префикс) Тогда
ИмяУзла = ЗаписьСоответствияПространствИмен.Префикс + ":" + ИмяУзла;
КонецЕсли;

КонецЕсли;
// -->

Возврат ВычислитьПредставлениеТекущегоПути(ТекущийУзел.РодительскийУзел) + "/" + ИмяУзла;

Иначе
Если ТекущийУзел.ТипУзла = ТипУзлаDOM.Документ Тогда
Возврат "";
ИначеЕсли ТекущийУзел.ТипУзла = ТипУзлаDOM.Атрибут Тогда
Возврат ВычислитьПредставлениеТекущегоПути(ТекущийУзел.ЭлементВладелец)
+ "/@" + ТекущийУзел.ИмяУзла;
Иначе
Возврат ТекущийУзел.ИмяУзла;
КонецЕсли;
КонецЕсли;

КонецФункции
Evil Beaver; +1 Ответить
23. Андрей Овсянкин (Evil Beaver) 24.10.13 16:38
(21) Поручик, да, история выражения и сохранение нужны. Недавно тоже XPath-ил с помощью обработки и их не хватало. Но, как ты выразился, сделать лень.
24. Яков Коган (Yashazz) 21.05.14 20:47
(23) Я с истории практически начал, в своей обработке, да и в текст её вываливать там можно. И сохранение тоже потребовалось сразу. А вот с пространствами имён даже заморачиваться не стал. Думал ещё точку начала поиска сделать изменяемой, но так и не освоил дзен, как заставить это работать без ошибки несоответствия.
25. Андрей Овсянкин (Evil Beaver) 22.05.14 13:27
(24) Yashazz, просто без пространств имен вроде как XPath не работает, или я что-то путаю?
Если есть файл с ПИ по умолчанию (т.е без префикса), то выражение ничего не найдет. Пример:

<root xmlns="http://someURI.com">
<elem>куку</elem>
</root>

Выражение /root/elem ничего не найдет, ибо XPath процессору нужен префикс для http://someURI.com. Это соответствие как раз для такого обхода - в файле без префиксов, а в выражении с префиксами: /ns:root/ns:elem. Соответствие префиксов у вас отсутствует и подобный файл обработать с помощью XPath не получится. Возможно, я что-то уже и путаю на старости лет, не уверен на 100%