XSLT: объединение файлов, но с большей производительностью процесса

У меня есть два XML-файла и я хочу слияния, критерий для этого слияния следующий:

Содержимое файла nodes1.xml:

<nodes>
  <node>
    <type>a</type>
    <name>joe</name>
  </node>
  <node>
    <type>b</type>
    <name>sam</name>
  </node>
  <node>
    <type>c</type>
    <name>pez</name>
  </node>
  <node>
    <type>g</type>
    <name>lua</name>
  </node>
  <node>
    <type>a</type>
    <name>tol</name>
  </node>
  <node>
    <type>c</type>
    <name>jua</name>
  </node>
</nodes>

Содержимое файла nodes2.xml:

<nodes>
  <node>
    <type>a</type>
    <name>jill</name>
  </node>
  <node>
    <type>c</type>
    <name>imol</name>
  </node>
  <node>
    <type>h</type>
    <name>teli</name>
  </node>
  <node>
    <type>f</type>
    <name>jopp</name>
  </node>
  <node>
    <type>c</type>
    <name>zolh</name>
  </node>
</nodes>

и по моему шаблону xsl я получаю:

<?xml version="1.0" encoding="UTF-8"?>
<nodes>
  <node tipo="a">
    <name>joe</name>
    <name>tol</name>
    <name>jill</name>
  </node>
  <node tipo="c">
    <name>pez</name>
    <name>jua</name>
    <name>imol</name>
    <name>zolh</name>
  </node>
  <node tipo="h">
    <name>teli</name>
  </node>
  <node tipo="f">
    <name>jopp</name>
  </node>
</nodes>

Мне нужно решение для повышения производительности. Мое текущее решение:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:variable name="Source2" select="document('nodes2.xml')/nodes/node"/>
  <xsl:variable name="Source1" select="document('nodes1.xml')/nodes/node"/>
  <xsl:template match="/nodes" >
    <nodes>
      <xsl:for-each-group select="node" group-by="type">
        <node tipo="{type}">
          <xsl:apply-templates select="$Source1[type=current-grouping-key()]/name"/>
          <xsl:apply-templates select="$Source2[type=current-grouping-key()]/name"/>
        </node>
      </xsl:for-each-group>
    </nodes>
  </xsl:template>

  <xsl:template match="name">
    <name><xsl:value-of select="."/></name>
  </xsl:template>
</xsl:stylesheet>

Я запускаю его с помощью java saxon:

$ java net.sf.saxon.Transform nodes2.xml mysolution.xsl

Я думаю, что «позор» иметь входной файл одновременно в переменной, но я не могу понять, как сделать это по-другому.

Я ценю помощь или указатель.

--Паулино


person Paulino Huerta    schedule 25.04.2013    source источник
comment
Почему это позор? Вы сталкиваетесь с проблемами производительности? Является ли входной XML таким же, как nodes1.xml или nodes2.xml? Если это так, вам нужна только одна переменная вместо двух.   -  person JLRishe    schedule 25.04.2013
comment
Нет. Я просто ищу решение, менее процедурное и, возможно, более функциональное, и в любом случае избегайте загрузки одного и того же входного файла в переменную. Я полагаю, что есть способ повысить производительность и уменьшить использование памяти. Обратите внимание, что входной файл используется только для группировки (чтобы знать разные ключи) ... мне не нравится   -  person Paulino Huerta    schedule 26.04.2013
comment
Что ж, как я уже сказал, если входной файл совпадает с одним из этих двух файлов, вы можете удалить одну из переменных и заменить одну из xsl:apply-templates на <xsl:apply-templates select="/nodes/node[type = current-grouping-key()]/name" />. Сомневаюсь, что вы сделаете это менее процедурным, чем оно есть.   -  person JLRishe    schedule 26.04.2013
comment
Это правда. Большое спасибо за ответ.   -  person Paulino Huerta    schedule 26.04.2013


Ответы (1)


Предполагая, что у вас есть второй из файлов в качестве основного ввода для кода XSLT, вы можете использовать следующее:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:param name="source1-uri" select="'nodes1.xml'"/>
  <xsl:variable name="doc1" select="doc($source1-uri)"/>

  <xsl:key name="by-type" match="nodes/node" use="type"/>

  <xsl:template match="/nodes" >
    <nodes>
      <xsl:for-each-group select="key('by-type', node/type, $doc1), node" group-by="type">
        <node tipo="{current-grouping-key()}">
          <xsl:copy-of select="for $n in current-group() return $n/name"/>
        </node>
      </xsl:for-each-group>
    </nodes>
  </xsl:template>

</xsl:stylesheet>

Я не уверен, имеет ли для вас значение порядок объединенных элементов name, но чтобы гарантировать, что с Saxon 9.5 я получу порядок, который вы разместили в своем образце результатов, мне пришлось использовать <xsl:copy-of select="for $n in current-group() return $n/name"/> вместо более короткого и более обычного <xsl:copy-of select="current-group()/name"/>.

Таким образом, это решение должно быть более эффективным, в основном за счет группировки всех входных node и, конечно же, простого использования current-group() вместо повторного выбора узлов с помощью предиката.

person Martin Honnen    schedule 26.04.2013
comment
Круто. Я не мог придумать что-то подобное. Большое спасибо, что ответили и поделились. Улучшает мое решение, я не сомневаюсь. - person Paulino Huerta; 27.04.2013