Как я могу реализовать определяемую пользователем функцию с именем в выражении xpath?

Я использую XSLT. Я знаю выражения встроенных функций Есть ли способ объявить именованную функцию в выражении xpath? потому что мне нужно имя функции для реализации рекурсивного вызова.


person cmf41013    schedule 27.12.2019    source источник
comment
Используя XSLT и xsl:function, вы можете сделать это легко, в чистом XPath используйте let.   -  person Martin Honnen    schedule 27.12.2019
comment
Как это сделать в чистом XPath? Хотите показать мне фрагмент кода?   -  person cmf41013    schedule 27.12.2019
comment
@cmf41013 cmf41013 Вот более свежий пример: stackoverflow.com/questions/58101443/   -  person Dimitre Novatchev    schedule 28.12.2019


Ответы (2)


В XSLT я бы просто предложил использовать xsl:function, поскольку таким образом ваша функция имеет имя, и вы можете вызывать ее рекурсивно внутри тела функции.

Что касается чистого XPath 3, Димитре исследовал этот путь несколько лет назад в https://dnovatchev.wordpress.com/2012/10/15/recursion-with-anonymous-inline-functions-in-xpath-3.-0-2/ с использованием функций let и более высокого порядка (функция, к сожалению, не поддерживается в Saxon 9 HE), я думаю, что его код использует синтаксис типа функции, не совсем соответствующий окончательной спецификации, поэтому его пример должен быть

let $f := 
    function($n as xs:integer,
             $f1 as function(xs:integer, function(*)) as xs:integer) as xs:integer {
        if ($n eq 0)
        then 1
        else $n * $f1($n -1, $f1)

    },
    $F := function($n as xs:integer) as xs:integer {
        $f($n, $f)
    }
return $F(5)

который можно было бы сократить до

let $f := 
    function($n as xs:integer,
             $f1 as function(xs:integer, function(*)) as xs:integer) as xs:integer {
        if ($n eq 0)
        then 1
        else $n * $f1($n -1, $f1)

    },
    $F := $f(?, $f)
return $F(5)

Я думаю, учитывая последний разрешенный синтаксис.

person Martin Honnen    schedule 27.12.2019
comment
@cmf41013 cmf41013 Более свежий пример см. в этом ответе: «рекурсивный родительский выбор xpath в плоской структуре»> stackoverflow.com/questions/58101443/ - person Dimitre Novatchev; 28.12.2019
comment
Мартин, выражение $F := $f(?, $f) великолепно! Однако это делает определение F() нечитаемым -- читателю не очевидно, каковы типы аргументов F(), и он должен изучить другие функции, чтобы понять, что это за типы... -- что-то, скорее, время трудоемки и подвержены ошибкам по сравнению с явным определением. Даже если мы разработаем инструмент, который будет генерировать полную сигнатуру F(), это все равно будет трудоемким и трудным для применения - другими словами, неудобно. - person Dimitre Novatchev; 28.12.2019
comment
@DimitreNovatchev, я понимаю вашу точку зрения, но я просто хотел представить вариант, который предлагает последняя версия XPath, я не собирался отдавать предпочтение этому способу по сравнению с вашим кодом, который я цитировал. В общем, я думаю, это зависит от точки зрения, например, в C#, когда они представили var для объявления переменных без их ввода, мои первоначальные мысли заключались в том, что мне это не нужно и я никогда не буду его использовать; но в настоящее время я считаю это весьма полезным, когда, например, использую Saxon в C # и копаюсь в его сложных API. - person Martin Honnen; 28.12.2019
comment
@DimitreNovatchev, а синтаксис заполнителя в XPath, безусловно, может сократить код, который вам нужно написать, например, когда вы импортируете модуль XQuery в XSLT и пытаетесь его использовать. - person Martin Honnen; 28.12.2019
comment
Да, но я пишу библиотеку функций, где каждая функция должна иметь четко определенную сигнатуру — как иначе мы сможем объяснить целевой аудитории, какой тип аргументов принимает функция и каково их значение? С другой стороны, внутренние или рабочие функции должны оставаться невидимыми, то есть фактическая реализация опубликованной функции должна быть скрыта. - person Dimitre Novatchev; 28.12.2019
comment
Я также заметил, что в курсе/учебнике более поучительно и полезно использовать полное имя типа, а не просто var. Это подчеркивает названия типов и помогает читателю быстрее привыкнуть к новым типам. - person Dimitre Novatchev; 29.12.2019

В XPath нельзя объявить именованную функцию; XPath 3.1 допускает только анонимные встроенные функции, и они не могут быть рекурсивными. Мне сказали, что есть способ добиться рекурсии в анонимных функциях, используя технику, называемую Y-комбинаторами, но это довольно ошеломляюще, и я никогда не думал об этом. Наилучший подход, как предлагает Мартин, состоит в том, чтобы поместить эту часть логики на уровень XSLT.

person Michael Kay    schedule 27.12.2019
comment
Re: это довольно ошеломляюще, и я никогда не думал об этом. ... Цитируя комментарий @martin_honnen выше: вы можете сделать это легко, в чистом XPath :) Вы оба говорите об одном и том же? - person Dimitre Novatchev; 28.12.2019
comment
Когда я попытался понять комбинатор Y, я определенно нашел его ошеломляющим; Я нахожу метод Дмитрия довольно простым и никогда не понимал, почему одному легко следовать, а другому нет. (Итак: я думаю, что MK и MH говорят об одном и том же, но я могу ошибаться.) - person C. M. Sperberg-McQueen; 28.12.2019