Объедините два xml-файла и получите один xml-вывод с помощью таблиц стилей Saxon и xslt

#xml #xslt #saxon

Вопрос:

Я хочу создать преобразование из нескольких xml-файлов только в один xml (Output.xml) используя саксонский. XML-файлы будут сгенерированы с помощью определенного файла merge.xslt, предоставленного my softwar (Векторное каноэ). Предположим, в одной папке у меня есть несколько файлов:

 test_InitStartOP_report0001.xml
test_InitStartOP_report0002.xml
test_InitStartOP_report0003.xml
 

Я хочу вывести один xml-файл с использованием этого шаблона из этой таблицы стилей :

 <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- Merge list of XML reports to one single report  -->
<!-- merge.xslt                                      -->
<!-- Version 1.2                                     -->
<!-- (c) 2005  Vector Informatik GmbH, Stuttgart     -->

<xsl:output method="xml" version="1.0" encoding="utf-8" standalone="yes"/>

<xsl:template match="/">
  <testmodule starttime="-" timestamp="-">
    <xsl:apply-templates select="//testmodule" />
    <xsl:variable name="testmoduleresult">
      <xsl:choose>
        <xsl:when test="//testmodule/verdict/@result='fail'">fail</xsl:when>
        <xsl:otherwise>pass</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <verdict time="-" timestamp="-" endtime="-" endtimestamp="-" result='{$testmoduleresult}' />
    <title>Test Report</title>
    
    <xsl:apply-templates select="//testmodule[1]/engineer|//testmodule[1]/testsetup|//testmodule[1]/sut|//testmodule[1]/hardware" />
    <xsl:apply-templates select="//testmodule/miscinfo|//testmodule/extendedinfo" />
    
  </testmodule>
</xsl:template>

<xsl:template match="testmodule">
  <testgroup>
    <xsl:apply-templates select="preparation|completion|testgroup|testcase|skipped|violation|moduledetails|externalref" />
    <xsl:copy-of select="title" />
    <xsl:copy-of select="description" />
    
    <!-- Write test module information -->
    <xsl:if test="testsetup">
      <xsl:for-each select="testsetup/xinfo|testsetup/info">
        <xsl:if test="local-name(.) != 'xinfo' or (name != 'Version' and name != 'Configuration' and name != 'Konfiguration' and name != 'Configuration Comment' and name != 'Konfigurationskommentar' and name != 'Windows Computer Name' and name != 'Windows Computer-Name' and not(starts-with(name, 'Nodelayer Module')) and not(starts-with(name, 'Nodelayer-Modul')))">
          <xsl:apply-templates select="." mode="tminfo" />
        </xsl:if>
      </xsl:for-each>
    </xsl:if>
  </testgroup>
</xsl:template>

<xsl:template match="info" mode="tminfo">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="xinfo" mode="tminfo">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="preparation">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="completion">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="testgroup">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="testcase">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="skipped">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="violation">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="moduledetails">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="miscinfo">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="extendedinfo">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="engineer">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="hardware">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="externalref">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="testsetup">
  <testsetup>
    <xsl:for-each select="xinfo">
      <xsl:if test="name = 'Version' or name = 'Configuration' or name = 'Konfiguration' or name = 'Configuration Comment' or name = 'Konfigurationskommentar' or name = 'Windows Computer Name' or name = 'Windows Computer-Name' or starts-with(name, 'Nodelayer Module') or starts-with(name, 'Nodelayer-Modul')">
        <xsl:copy-of select="." />
      </xsl:if>
    </xsl:for-each>
  </testsetup>
</xsl:template>

<xsl:template match="sut">
  <xsl:copy-of select="." />
</xsl:template>

</xsl:stylesheet>
 

Я попытался использовать Saxon в Cmd, используя эту строку cmd :

 java -jar saxon-he-10.5.jar -xsl:merge.xslt -s:"test_InitStartOP_report0001.xml;test_InitStartOP_report0002.xml" -o:Output.xml
 

Но это не работает, кто-нибудь знает, как я могу решить эту проблему?

Комментарии:

1. Поэтому, возможно, спросите своего поставщика программного обеспечения, как этот код XSLT должен вызываться или использоваться с несколькими документами. Что касается Саксона, я думаю -s , что для этого нужно выбрать один документ. В XSLT в целом у вас есть document функция для извлечения других входных документов, в XSLT 2 и 3 у вас дополнительно есть doc функция, и Saxon позволяет вам использовать collection и uri-collection обрабатывать последовательность файлов.

Ответ №1:

Возможно, я не совсем понял это требование, но я предполагаю, что, когда вы напишете

 <xsl:apply-templates select="//testmodule[1]/engineer|//testmodule[1]/testsetup|//testmodule[1]/sut|//testmodule[1]/hardware" />
<xsl:apply-templates select="//testmodule/miscinfo|//testmodule/extendedinfo" />
    
 

На самом деле вы хотите выбрать testModule элементы во всех входных документах. Если это так, то первым делом нужно иметь переменную $allInputs , значением которой является набор входных документов, а затем изменить эти выражения, например

 <xsl:apply-templates select="$allInputs//testModule/....."/>
 

Тогда возникает вопрос, как привязать переменную $allInputs к этому набору документов. Есть несколько способов сделать это:

  • используйте функцию collection()
  • используйте функцию document() со списком URI
  • передайте все документы в качестве одного параметра таблицы стилей

Поскольку вы работаете из командной строки, самым простым подходом может быть изменение командной строки для предоставления параметра таблицы стилей, содержащего список URI, разделенных точкой с запятой:

 inputFiles="test_InitStartOP_report0001.xml;test_InitStartOP_report0002.xml"
 

а затем в таблице стилей вы можете сделать

 <xsl:param name="inputFiles" as="xs:string" required="yes"/>
<xsl:variable name="allInputs" select="tokenize($inputFiles, ';')!document(.)" as="document-node()*"/>
 

Обратите внимание, что в этом случае вам не нужен «основной входной документ» — удалите опцию-s в командной строке, используйте вместо нее-it и измените <xsl:template match="/"> на <xsl:template name="xsl:initial-template"> .