#xml #xslt #xslt-2.0
#xml #xslt #xslt-2.0
Вопрос:
Это мой файл xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://xmlns.jcp.org/xml/ns/persistence">
<xsl:param name="childPath"/>
<xsl:param name="childNode"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[local-name()=$childNode]">
<xsl:apply-templates select="document($childPath)//class"/>
</xsl:template>
</xsl:stylesheet>
Идея в том, что у меня есть один родительский (шаблонный) XML-файл и N дочерних XML-файлов. Итак, я беру родительский и вызываю этот файл xslt для первого дочернего XML-файла, для второго и так далее. Этот файл xslt я вызываю с помощью maven-xml-plugin, и для каждого вызова мне нужно установить transormationSet, который является довольно подробным.
Итак, я хочу вызвать этот файл xslt только один раз и передать все параметры в виде списка или карты. Например
$childNodes = nodeOne;nodeTwo;nodeThree
$childPaths = pathOne;pathTwo;pathTree
или как карта:
$children = nodeOne:pathOne;nodeTwo:pathTwo
Кто-нибудь может сказать, как заставить мой файл xslt работать с такими параметрами списка / карты?
Комментарии:
1. Какую версию какого процессора XSLT вы используете? Saxon 9.8 и более поздние версии и AltovaXML 2017 R3 и более поздние версии поддерживают XSLT 3 с картами XPath 3.1. например
<xsl:param name="children" select="map { 'nodeOne' : 'pathOne', 'nodeTwo' : 'pathTwo' }"/>
.2. @MartinHonnen Я использую net.sf.saxon 8.7. ( mvnrepository.com/artifact/net.sf.saxon/saxon )
3. Это даже предварительная версия XSLT 2.
4. @MartinHonnen Я могу использовать этот mvnrepository.com/artifact/net.sf.saxon/Saxon-HE/10.3 если это будет необходимо.
Ответ №1:
Используя карту XPath 3.1 / XSLT 3.0, поддерживаемую в Saxon 9.8 и более поздних версиях или Saxon-JS 2 или Altova XML 2017 R3 и более поздних версиях, вы можете использовать
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:param name="children" as="map(xs:string, xs:string)" select="map { 'nodeOne' : 'pathOne', 'nodeTwo' : 'pathTwo' }"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="*[local-name()=map:keys($children)]">
<xsl:apply-templates select="document($children(local-name()))//class"/>
</xsl:template>
</xsl:stylesheet>
В качестве альтернативы придерживаться ваших строковых значений, содержащих списки значений, разделенных точкой с запятой:
<xsl:param name="childNodes">nodeOne;nodeTwo;nodeThree</xsl:param>
<xsl:param name="childPaths">pathOne;pathTwo;pathTree</xsl:param>
<xsl:variable name="childNodesSeq" select="tokenize($childNodes, ';')"/>
<xsl:variable name="childPathsSeq" select="tokenize($childPaths, ';')"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="*[local-name()=$childNodesSeq]">
<xsl:apply-templates select="document($childPathsSeq[index-of($childNodesSeq, local-name(current()))])//class"/>
</xsl:template>
Комментарии:
1. Не могли бы вы сказать, в каком формате я должен передавать дочерние элементы. Я имею в виду
<parameter> <name>children</name><value>'nodeOne':'pathOne'</value></parameter>
? Я спрашиваю, как я получаюsupplied value ... is an atomic value
.2. @Shtirlits, как / откуда вы передаете параметры? Из командной строки Saxon? Из программы Java? Если да, то какой API вы используете? В коде Java я бы использовал saxonica.com/html/documentation/javadoc/net/sf/saxon/s9api /. …
3. Я использую maven-xml-plugin, см. Раздел Параметров здесь mojohaus.org/xml-maven-plugin/examples /…
4. @Shtirlits, извините, я не знаю, как они представляют значения XDM 2 или XDM 3.1 в своем механизме параметров, подумайте о том, чтобы соответствующим образом пометить ваш вопрос, чтобы найти экспертные знания по этой конкретной теме.
5. Хорошо, я понимаю. Но как это будет представлено для командной строки Java? Может быть, это то же самое…
Ответ №2:
Один из способов — ввести режим шаблона и перебирать пары имя / путь
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://xmlns.jcp.org/xml/ns/persistence">
<xsl:param name="children" select="'name1:path1;name2:path2'"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="here" select="."/>
<xsl:for-each select="tokenize($children,';')">
<xsl:apply-templates mode="child" select="$here">
<xsl:with-param name="name" tunnel="true" select="tokenize(.,':')[1]"/>
<xsl:with-param name="path" tunnel="true" select="tokenize(.,':')[2]"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="*" mode="child">
<xsl:param name="name" tunnel="true"/>
<xsl:param name="path" tunnel="true"/>
<xsl:if test="local-name()=$name">
<xsl:apply-templates select="document($path)//class"/>
</xsl:if>
<xsl:apply-templates mode="child"/>
</xsl:template>
</xsl:stylesheet>