barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)
Показаны сообщения с ярлыком xpath. Показать все сообщения
Показаны сообщения с ярлыком xpath. Показать все сообщения

вторник, 16 декабря 2014 г.

XPath 1.0: тернарный оператор

Как такового, тернарного оператора в XPath 1.0 нет. Можно реализовать аналогичное поведение, правда, немного замысловатым образом. Следующее выражение даст $stringA, если $cond = true, и $stringB - в противном случае:
concat(substring($stringA, 1 div $cond), substring($stringB, 1 div not($cond)))

WSO2 ESB 4.5.1: использование пространства имен http://ws.apache.org/ns/synapse в XPath-выражениях

Проблема

Есть прокси-сервис, в нем есть property-медиатор, у которого в xpath-выражении в атрибуте expression используется пространство имен "http://ws.apache.org/ns/synapse" с помощью некоторого префикса, который объявлен в этом же property-теге:
<property name="XXXProp" expression="//syn:abc/text()" xmlns:syn="http://ws.apache.org/ns/synapse"/>
Если прокси-сервис отредактировать через веб-консоль шины, объявление префикса пропадает, после чего property-медиатор, естественно, начинает выдавать ошибки из-за неизвестного префикса пространства имен. Если объявление префикса перенести из медиатора выше (хотя даже в сам корневой тег прокси-сервиса), ситуация не меняется.

Решение

Похоже на баг, и вызван он скорее всего тем, что сам конфигурационный xml прокси-сервиса имеет пространство имен по-умолчанию "http://ws.apache.org/ns/synapse". Копаться в исходниках времени не было, поэтому пришлось воспользоваться workaround'ом:
<property name="XXXProp" expression="//*[local-name()='abc']/text()" />

суббота, 11 октября 2014 г.

IE8: аналог getElementsByTagNameNS для объекта Microsoft.XMLDOM

Задача

В Internet Explorer 8 есть объект Microsoft.XMLDOM (передаваемый dojo-вским xjrPost в обработчик success), нужно из него вытащить элемент по имени тега, причем элемент имеет пространство имен.

Решение

Немного замысловато (здесь xml - объект Microsoft.XMLDOM):

xml.setProperty("SelectionNamespaces", "xmlns:myns='http://myns.com/ns'");
xml.setProperty("SelectionLanguage", "XPath");
alert(xml.documentElement.selectNodes("//myns:MyElement").length);

вторник, 4 декабря 2012 г.

Synapse: использование пространств имен в Xpath в конфигурации

Чтобы конфигурации Synapse использовать пространства имен в выражениях Xpath, нужно в в том теге, в котором xpath используется (или в любом теге-предшественнике этого тега) объявить нужный namespace, после чего его префикс можно будет использовать в Xpath:
<switch source="count($body/myns:MyNode)" xmlns:myns="http://my.ns"

среда, 21 ноября 2012 г.

WSO2 ESB: Получение имени файла, полученного по траспорту VFS, в цепочке медиации

Получается имя файла XPath-выражением:
synapse:get-property('transport','FILE_NAME')
Например, логируется это свойство в цепочке медиации так:
<log level="custom">
<property name="vfsfilename" expression="synapse:get-property('transport','FILE_NAME')"/>
</log>
Как получить доступ к транспортному заголовку ('FILE_NAME' или любому другому) из пользовательского медиатора, я писал тут: http://barbitoff.blogspot.ru/2012/11/wso2-esb.html. 

среда, 22 февраля 2012 г.

xforms:case и xpath в атрибуте "selected"

В атрибуте "selected" использовать xpath нельзя, его значение интерпретируется как текст, и любое значение, отличное от true, приводит к скрытию case`а (если все case`ы оказываются скрыты, первый из них все же отображается). По крайней мере в Orbeon это так.

вторник, 21 февраля 2012 г.

Orbeon: отличие xpath-функций instance() и xxforms:instance()

xxforms:instance() выбирает сущность по идентификатору также, как и стандартная функция instance() с той лишь разницей, что:
  1. Не учитывает область видимости, заданную текущей моделью (выбранной атрибутом "model")
  2. Осуществляет поиск в областях видимости вышестоящих XBL-компонентов
, в то время как instance() ищет только в текущей модели текущего компонента.

вторник, 13 декабря 2011 г.

Orbeon XPath: получение свойств из properties-local.xml

XPath-расширения Орбеона позволяют получать значения свойств, заданные в настроечном файле properties-local.xml (расположенном в 'WEB-INF\resources\config'). Так, например, XPath-выражение:
xxforms:property('some.property.name')
вернет содержимое свойства:
<property as="xs:anyURI"  name="some.property.name" value="http://ya.ru"/>

XPath trim(), а также выбор узлов, содержащих только пробелы

Функции trim(), удаляющей из строки концевые и начальные пробелы, в XPath нет, однако есть normalize-space(), делающая даже немного больше: она к тому же преобразует последовательности из нескольких пробелов внутри строки в один пробел.
Таким образом, условие для выбора узлов, пустых или содержащих только пробелы, выглядит следующим образом:
[normalize-space(text())='']

пятница, 2 декабря 2011 г.

Orbeon: создание XML-элемента с пространством имен с помощью XPath

Задача: 

Создать элемент с пространством имен, описанным в этом же элементе (установить xmlns как атрибут, передав его вторым параметром функции xxforms:element, нельзя - Orbeon просто проигнорирует атрибуты с именем xmlns или из пространства имен xmlns). Например:
<foo:mytag xmlns:foo='some-name-space'/>

Решение:

xxforms:element(QName('some-name-space'),'foo:mytag'))

или, если, к примеру, нужно взять namespace другого узла:

xxforms:element(QName(namespace-uri(/path/to/other/node),'foo:mytag')

Правда, такое создание элемента связано со следующей проблемой (вернее, скорее всего, багом орбеона): при использовании пространства имен по-умолчанию (т.е. передавая в QName имя элемента без пространства имен), элемент не создается. Если пытаться выполнить эту операцию в XForms Inspector, вылетает "java.lang.StringIndexOutOfBoundsException: String index out of range: -1", при использовании этого XPath в других местах он также приводит к некорректному поведению орбеона. Другого способа создавать элементы с пространством имен по-умолчанию я не нашел, разве что описывать элемент строкой, после чего парсить её с помощью saxon:parse:

saxon:parse('<mytag xmlns=''some-name-space''/>')
В таком случае, однако, нельзя одновременно с созданием элемента добавить ему потомков без их сериализации в строку, как это позволяет сделать xxforms:element.

четверг, 8 сентября 2011 г.

XPath: определение возраста

if($birthDate='') 
	then '' 
	else year-from-date(xs:date(local-date()))-year-from-date($birthDate)
		-(if(month-from-date($birthDate) > month-from-date(xs:date(local-date())))
			then 1
			else (if(month-from-date($birthDate) < month-from-date(xs:date(local-date())))
					then 0
					else (if(day-from-date($birthDate) > day-from-date(xs:date(local-date())))
							then 1
							else 0
						)
				)
			)
Возможно, можно как-то сделать это проще, но я пока способа не нашел. Вычитание дат дает результат типа xs:dayTimeDuration вместо xs:yearMonthDuration, из которого было бы удобно извлечь число лет. А вот по числу дней число лет определить очень сложно из-за високосных годов.

вторник, 6 сентября 2011 г.

XPath: проверка, что между указанной датой и текущей прошло меньше определенного количества лет

$dateToCheck + xs:yearMonthDuration('P120Y0M') > xs:date(local-date())- проверяет, что с даты $dateToCheck (типа xs:date) до текущей локальной даты прошло не более 120 лет. Если   $dateToCheck - строка, то нужно сделать xs:date($dateToCheck). 

понедельник, 29 августа 2011 г.

Ошибка XPath: "Required item type of first operand of '|' is node(); supplied value has item type ..."

Проблема: при попытке объединения последовательностей в XPath с помощью оператора "|" или "union", возникает ошибка "Required item type of first operand of '|' is node(); supplied value has item type xs:string" (вместо "xs:string" может быть другой тип если последовательности состоят из элементов другого типа).
Причина: Оператор объединения в XPath действительно позволяет логически объединять (т.е. создавать из нескольких последовательностей одну, исключая повторяющиеся элементы) только последовательности из узлов (node). Любые другие последовательности (из строк, чисел и пр.) этим оператором не поддерживаются.

пятница, 26 августа 2011 г.

org.orbeon.saxon.trans.XPathException: An empty sequence is not allowed as the value of variable $section-holder

Проблема: при попытке получить pdf-ку из заполненной в orbeon формы вместо pdf-ки вываливается исключение "org.orbeon.saxon.trans.XPathException: An empty sequence is not allowed as the value of variable $section-holder".

Причина:
  • где-то в форме есть секция (fr:section), bind которой не имеет id вида "{sectionRootTagInModel}-bind", где {sectionRootTagInModel} - имя тэга в модели, к которому привязана секция с помощью конструкции bind. Т.е. секции должны быть привязаны к элементам модели следующим образом: <xforms:bind id="{sectionRootTagInModel}-bind " nodeset="{sectionRootTagInModel}"> для секции, объявленой как <fr:section id="{sectionRootTagInModel}-section" bind="{sectionRootTagInModel}-bind"> (использование другого id самой секции вроде как проблем не вызывает). 
  • в форме используются вложенные друг в друга bind`ы. Секции вкладывать друг в друга можно, но вот bind`ы - нет (за исключением вложения всех биндов в общий бинд к корневому тегу модели).

Решение: всегда присваивать bind`ам секций id вида "{sectionRootTagInModel}-bind". Не использовать вложенные секции