XSD assert: умножить все значения в последовательности - PullRequest
0 голосов
/ 08 декабря 2018

У меня есть XML-документ, который выглядит следующим образом:

<Output>
    <Integer start="0 0 0 0 0 0 0"/>
    <Dimensions>
        <Dimension value="2"/>
        <Dimension value="3"/>
    </Dimensions>
</Output>

У меня также есть XSD-файл, который определяет соответствующую структуру.Начальный атрибут определяется как список целых чисел.Внутри этого XSD-файла я хочу иметь утверждение, которое проверяет, равно ли количество значений в этом списке умножению всех атрибутов значений элементов Dimension.В этом случае 2 * 3 = 6 значений должны быть определены в начале.

Это было бы что-то вроде

<xs:assert test="count(data(./Integer/@start)) = multiply(./Dimensions/Dimension/@value) "/>

Моя проблема в том, как написать умножение, аналогичное сумме, но с умножением вместо сложения.Есть ли возможность добавить функции в документ XSD?Или есть возможность переписать тест assert, чтобы выполнить мое требование?

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

Утверждения XSD 1.1 ограничены XPath 2.0, что затрудняет это;нет доступа к функции XPath 3.1 fold-left() или к пользовательским функциям (которые допускают рекурсию).

Некоторые процессоры XSD 1.1 могут снять это ограничение (вы можете настроить Saxon для поддержки XPath 3.1), но это выходит за рамки спецификации.

Если вы готовы ограничить количество измерений, которые вы можетесделайте это так

number(if (exists(Dimension[1])) then Dimension[1]/@value else 1) *
number(if (exists(Dimension[2])) then Dimension[2]/@value else 1) *
number(if (exists(Dimension[3])) then Dimension[3]/@value else 1) *
... etc

Но я не думаю, что есть общее решение, использующее чистый XSD 1.1 + XPath 2.0.

С включенной XPath 3.1 вы могли бы сделать

count(...) = fold-left(Dimension/@value, 1, 
               function($total, $next){$total*number($next)})
0 голосов
/ 08 декабря 2018

Если я вас правильно понимаю, вы запрашиваете функцию умножения, которая работает со списками / последовательностями.

Поскольку такой встроенной функции afaik нет, для этого требуется определенная пользователем рекурсивная функция (в среде функционального программирования XQuery), например:

declare function local:rec-multiply($seq, $count) {
  if(empty($seq)) then ()
  else
    let $prod  := $seq[1], 
        $count := $count * $prod
    return (
      <count>{ $count }</count>,
      local:rec-multiply($seq[position() > 1], $count)
    )
};

count(tokenize(//Integer/@start, '\s')) 
  = local:rec-multiply(//Dimension/@value, 1)[last()]

Online Demo

Предупреждение: для этого кода требуется XQuery 3+, а обычные процессоры XSD поддерживают только XPath 2.0 (на самом деле часто это только подмножество).Если вы отмените это ограничение, вы также можете использовать функции XQuery для фальцевания влево / вправо, как упомянул Майкл Кей.

Однако, в конце концов, скорее всего, гораздо проще просто извлечь эти значения и выполнитьумножение и проверка на вашем языке программирования общего назначения.

...