XSLT 2.0 список параметров / сопоставление с для каждого

#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>