Группируйте XML с помощью xslt на основе заголовка или ввода документа - PullRequest
0 голосов
/ 17 февраля 2019

Как сгруппировать XML, используя xlst для приведенного ниже XML-кода.Ниже приведен входной XML: я использую этот входной XML для импорта в систему ERP.

 <row>
        <Ref>1</Ref>
        <Code>IT001</Code>
        <Qty>11</Qty>
    </row>
    <row>
        <Ref>1</Ref>
        <Code>IT002</Code>
        <Qty>21</Qty>
    </row>
    <row>
        <Ref>2</Ref>
        <Code>IT002</Code>
        <Qty>12</Qty>
    </row>

Ниже приведены выходные или ожидаемые XML: система ERP обычно принимает одну строку на документ, и ее братья и сестрыстрок документа.Таким образом, требуется следующий желаемый результат:

<Document>
    <Ref>1</Ref><Lines>
        <Item>
            <Code>IT001</Code>
            <Qty>11</Qty>
        </Item>
        <Item>
            <Code>IT002</Code>
            <Qty>21</Qty>
        </Item>
    </Lines>
</Document>
<Document>
    <OrderRef>2</OrderRef>
    <Lines>
        <Item>
            <Code>IT002</Code>
            <Qty>12</Qty>
        </Item>
    </Lines>
</Document>

1 Ответ

0 голосов
/ 17 февраля 2019

Давайте начнем с исправления вашего исходного XML:

Должен быть только один корневой элемент (я назвал его Root ), и внутри него может бытьнесколько (например, Document ) элементов.

Шаблон, выполняющий преобразование, должен соответствовать элементу Root .

Как видно из ожидаемого результата,Вы хотите сгруппировать элементы Document по DocumentRef , поэтому в приведенном ниже скрипте есть соответствующая инструкция xsl: for-each-group .

Для каждой такой группы должен быть выходной элемент Document , а внутри него Ref элемент со значением текущего ключа группировки.

Тогда должен быть Элемент строк и внутри него для каждого члена текущей группы должен быть элемент Item , а внутри него 2 дочерних элемента с необходимыми значениями из исходного элемента.

Таким образом,Весь сценарий может выглядеть следующим образом:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:template match="Root">
    <xsl:copy>
      <xsl:for-each-group select="Document" group-by="DocumentRef">
        <Document>
          <Ref><xsl:value-of select="current-grouping-key()"/></Ref>
          <Lines>
            <xsl:for-each select="current-group()">
              <Item>
                <ItemCode><xsl:value-of select="DocumentLines/ItemCode"/></ItemCode>
                <Qty><xsl:value-of select="DocumentLines/ItemQty"/></Qty>
              </Item>
            </xsl:for-each>
          </Lines>
        </Document>      
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
</xsl:transform>

Рабочий пример, включая исправленный ввод, см. http://xsltransform.net/eieE3PX

Версия XSLT 1.0

В XSLT 1.0 это также возможно, используя Muenchian Grouping :

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:key name="groups" match="row" use="OrderRef"/>

  <xsl:template match="Payload">
    <xsl:copy>
      <xsl:apply-templates select="row[generate-id() = generate-id(
        key('groups', OrderRef)[1])]"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="row">
    <Document>
      <Ref><xsl:value-of select="OrderRef"/></Ref>
      <CardCode><xsl:value-of select="CustomerCode"/></CardCode>
      <Lines>
        <xsl:for-each select="key('groups', OrderRef)">
          <Item>
            <ItemCode><xsl:value-of select="ItemCode"/></ItemCode>
            <Qty><xsl:value-of select="Quantity"/></Qty>
          </Item>  
        </xsl:for-each>
      </Lines>
    </Document>
  </xsl:template>
</xsl:transform>

Первым шагом является создание xsl:key.Каждый ключ должен иметь name, чтобы ссылаться на него позже.match определяет, какие элементы включить в этот ключ , а use определяет ключ группировки.

Затем посмотрите:

<xsl:apply-templates select="row[generate-id() = generate-id(
  key('groups', OrderRef)[1])]"/>

Это "вызывает действие"(в данном случае xsl:apply-templates) для первого объекта в каждой группе.

Остальная часть кода из моего исходного решения была перемещена в шаблон, соответствующий строка .

Начальная часть выполняет действия для текущей группы (генерирует выходные данные Document , Ref , CardCode и Lines elements).

Остальные (xsl:for-each) выполняют действия для отдельных членов текущей группы, генерируя элементы Item , ItemCode и Кол-во .

Я обновил ваше решение в xsltransform , поэтому вы можете просмотреть его на http://xsltransform.net/jxWYjW2/2

Обратите внимание, что я изменил XSLT-движок на Saxon 6.5.5 .Вы также можете переключить его на Xalan , хотя тогда вы потеряете отступ.

Если этот подход для вас новый, возможно, вам следует прочитать немного о generate-id и мюнхенская группировка сама.Даже StackOverflow содержит много сообщений об этих проблемах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...