Группировка вывода с использованием XSLT 1.0 - PullRequest
0 голосов
/ 04 марта 2019

Мне дали следующий XML (созданный кем-то из электронной таблицы Excel)

<Records>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section A</Section>
    <label>Option X 1</label>
    <Keyword>Unique KW 1</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section B</Section>
    <label>Option X 2</label>
    <Keyword>Unique KW 2</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 2</Domain>
    <Section>Section A</Section>
    <label>Option X 3</label>
    <Keyword>Unique KW 3</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section A</Section>
    <label>Option X 4</label>
    <Keyword>Unique KW 4</Keyword>
    <Control>Checkbox</Control>
    <Default>FALSE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section B</Section>
    <label>Option X 5</label>
    <Keyword>Unique KW 5</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 2</Domain>
    <Section>Section B</Section>
    <label>Option X 6</label>
    <Keyword>Unique KW 6</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section A</Section>
    <label>Option X 7</label>
    <Keyword>Unique KW 7</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
</Records>

И меня попросили преобразовать его в следующее, используя XSLT 1.0

<Configuration>
<Domain name="Domain 1">
    <Section name="Section A">
        <Option keyword="Unique KW 1" name="Option X 1">
            <Control type="Checkbox" default="True" />
        </Option>
        <Option keyword="Unique KW 3" name="Option X 3">
            <Control type="Checkbox" default="True" />
        </Option>
        <Option keyword="Unique KW 7" name="Option X 7">
            <Control type="Checkbox" default="True" />
        </Option>
    </Section>
    <Section name="Section B">
        <Option keyword="Unique KW 2" name="Option X 2">
            <Control type="Checkbox" default="True" />
        </Option>
        <Option keyword="Unique KW 5" name="Option X 5">
            <Control type="Checkbox" default="True" />
        </Option>
    </Section>
</Domain>
<Domain name="Domain 2">
    <Section name="Section A">
        <Option keyword="Unique KW 3" name="Option X 3">
            <Control type="Checkbox" default="True" />
        </Option>       
    </Section>
    <Section name="Section B">
        <Option keyword="Unique KW 6" name="Option X 6">
            <Control type="Checkbox" default="True" />
        </Option>       
    </Section>
</Domain>
</Configuration>

В прошлом я использовал XSLT в ограниченном объеме, но я изо всех сил пытаюсь получить один элемент (например, домен и раздел), вывод, который я получаю, - один на элемент в источнике, где мне нужно 1 на значение висточник (если это имеет смысл).Я просто получаю много

доменов вместо двух (домен 1 и домен 2), то же самое с разделом

Есть ли способ сделать это с XSLT 1.0 или я простотратить мое время?

(Кроме того, данные, которые я привел, являются примером, отредактированным для удаления конфиденциальных данных и размера, есть гораздо больше доменов и разделов и т. д.)

(Маленький яуже так далеко)

<xsl:stylesheet version="1.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:ms="urn:schemas-microsoft-com:xslt"
            xmlns:dt="urn:schemas-microsoft-com:datatypes">
<xsl:output media-type="xml" indent="yes" />

<xsl:template match="/Records">
<Configuration>
  <xsl:for-each select="record/Domain">
    <Domain name="{text()}">
    <Section name="{../Section/text()}">
      <Option keyword="{../Keyword/text()}">
        <Control type="{../Control/text()}"/>
      </Option>
    </Section>
    </Domain>
  </xsl:for-each>
</Configuration>
</xsl:template>
</xsl:stylesheet>

РЕДАКТИРОВАТЬ: После просмотра ссылки Майклза (спасибо) я все ближе.Внешняя группа (домен) работает, но внутренняя группа не

  <xsl:key name="domain-name" match="record" use="Domain" />
  <xsl:key name="section-name" match="record" use="Section" />

  <xsl:template match="/Records">
    <Configuration>
      <xsl:for-each select="record[count(. | key('domain-name', Domain)[1]) = 1]">
        <xsl:sort select="Domain" />
        <Domain name="{Domain}">
          <xsl:for-each select="record[count(. | key('section-name', Section)[1]) = 1]">
            <xsl:sort select="Section" />
              <Section name="{Section}">
                <Option keyword="{Keyword/text()}">
                  <Control type="{Control/text()}"/>
                </Option>
              </Section>
            </xsl:for-each>
          </Domain>
        </xsl:for-each>
      </Configuration>
    </xsl:template>

дает мне

  <Configuration>
    <Domain name="Domain 1" />
    <Domain name="Domain 2" />
  </Configuration>

1 Ответ

0 голосов
/ 04 марта 2019

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

<xsl:key name="section-name" match="record" use="concat(Domain, '|', Section)" />

Затем необходимо изменить внутреннюю xsl:for-each, чтобы использоватьу них новый ключевой формат.Но также потому, что вы делаете xsl:for-each select="group....", который не будет работать, потому что вы в данный момент находитесь на record, и поэтому внутренний xsl:for-each ищет дочерний элемент, также называемый record.Это должно выглядеть так, что учитывает только record элементов для текущего Domain значения

<xsl:for-each select="key('domain-name', Domain)[count(. | key('section-name', concat(Domain, '|', Section))[1]) = 1]">

Попробуйте это XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />

  <xsl:key name="domain-name" match="record" use="Domain" />
  <xsl:key name="section-name" match="record" use="concat(Domain, '|', Section)" />

  <xsl:template match="/Records">
    <Configuration>
      <xsl:for-each select="record[count(. | key('domain-name', Domain)[1]) = 1]">
        <xsl:sort select="Domain" />
        <Domain name="{Domain}">
          <xsl:for-each select="key('domain-name', Domain)[count(. | key('section-name', concat(Domain, '|', Section))[1]) = 1]">
            <xsl:sort select="Section" />
              <Section name="{Section}">
                <Option keyword="{Keyword/text()}">
                  <Control type="{Control/text()}"/>
                </Option>
              </Section>
            </xsl:for-each>
          </Domain>
        </xsl:for-each>
      </Configuration>
    </xsl:template>
</xsl:stylesheet>

Похоже, вам также нужен третийуровень группировки, на Keyword, но вы должны уладить это сейчас (вам понадобится ключ, чтобы рассмотреть Domain, Section и Keyword)

...