XSL объединяет несколько XML записей в одном файле - PullRequest
0 голосов
/ 29 января 2020

У меня есть один XML файл, содержащий несколько записей. У каждой записи есть ключ. Я хотел бы выбрать все записи по ключу и свернуть каждую в одну XML запись. Некоторые данные в каждой записи XML повторяются, и в них есть пустые элементы. Я также хотел бы удалить дубликаты и пустые теги.

Ввод

<Data>
    <Record>
        <Key>12345</Key>
        <Number>09095I</Number>
        <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
        <Text_Field_2>This is Text Field 2</Text_Field_2>
        <Author>A1</Author>
        <Author>A2</Author>
        <Author></Author>
        <Author>A1</Author>
        <Author>A2</Author>
        <Author>A3</Author>
        <Author></Author>
        <Author>A1</Author>
        <Date>10/12/2019</Date>
        <Summary>Record 1: Summary 1 Text</Summary>
    </Record>
    <Record>
        <Key>12345</Key>
        <Number>09095I</Number>
        <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
        <Text_Field_2>This is Text_Field_2</Text_Field_2>
        <Author>A2</Author>
        <Author></Author>
        <Author>A1</Author>
        <Author>A3</Author>
        <Author></Author>
        <Author>B2</Author>
        <Author></Author>
        <Author>B2</Author>
        <Date>10/12/2019</Date>
        <Summary>Record 2: Summary 1 Text</Summary>
    </Record>
    <Record>
        <Key>23456</Key>
        <Number>43095I</Number>
        <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
        <Text_Field_2>This is Text_Field_2</Text_Field_2>
        <Author>AA2</Author>
        <Author></Author>
        <Author>AA1</Author>
        <Author>AA3</Author>
        <Author></Author>
        <Author>AA3</Author>
        <Author>BB2</Author>
        <Author></Author>
        <Author>AA3</Author>
        <Date>01/12/2020</Date>
        <Summary>Record 1: Summary 1 Text</Summary>
    </Record>
    <Record>
        <Key>23456</Key>
        <Number>43095I</Number>
        <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
        <Text_Field_2>This is Text_Field_2</Text_Field_2>
        <Author>AA1</Author>
        <Author>AA3</Author>
        <Author></Author>
        <Author>CC2</Author>
        <Author></Author>
        <Author>AA1</Author>
        <Author>CC2</Author>
        <Date>01/12/2020</Date>
        <Summary>Record 2: Summary 1 Text</Summary>
    </Record>
    <Record>
        <Key>23456</Key>
        <Number>43095I</Number>
        <Text_Field_1>Record 3: This is Text Field 1</Text_Field_1>
        <Text_Field_2>This is Text_Field_2</Text_Field_2>
        <Author>AA1</Author>
        <Author>AA3</Author>
        <Author></Author>
        <Author>CC2</Author>
        <Author></Author>
        <Author>AA1</Author>
        <Author>CC3</Author>
        <Date>01/12/2020</Date>
        <Summary>Record 3: Summary 1 Text</Summary>
    </Record>
    <Record>
        <Key>778899</Key>
        <Number>998822I</Number>
        <Text_Field_1>Record 1: This is Text_Field_1</Text_Field_1>
        <Text_Field_2>This is Text_Field_2</Text_Field_2>
        <Author>A2</Author>
        <Author></Author>
        <Author>D1</Author>
        <Author>D2</Author>
        <Author></Author>
        <Author>D3</Author>
        <Author>D33</Author>
        <Author></Author>
        <Author>D33</Author>
        <Date>10/12/2019</Date>
        <Summary>Record 1: Summary 1 Text</Summary>
    </Record>
</Data>

Желаемый вывод

<Data>
    <Record>
        <Key>12345</Key>
        <Number>09095I</Number>
        <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
        <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
        <Text_Field_2>This is Text Field 2</Text_Field_2>
        <Author>A1</Author>
        <Author>A2</Author>
        <Author>A3</Author>
        <Author>B2</Author>
        <Date>10/12/2019</Date>
        <Summary>Record 1: Summary 1 Text</Summary>
        <Summary>Record 2: Summary 1 Text</Summary>
    </Record>

    <Record>
        <Key>23456</Key>
        <Number>43095I</Number>
        <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
        <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
        <Text_Field_1>Record 3: This is Text Field 1</Text_Field_1>
        <Text_Field_2>This is Text_Field_2</Text_Field_2>
        <Author>AA1</Author>
        <Author>AA2</Author>
        <Author>AA3</Author>
        <Author>BB2</Author>
        <Author>CC2</Author>
        <Author>CC3</Author>
        <Date>01/12/2020</Date>
        <Summary>Record 1: Summary 1 Text</Summary>
        <Summary>Record 2: Summary 1 Text</Summary>
        <Summary>Record 3: Summary 1 Text</Summary>
    </Record>
    <Record>
        <Key>778899</Key>
        <Number>998822I</Number>
        <Text_Field_1>Record 1: This is Text_Field_1</Text_Field_1>
        <Text_Field_2>This is Text_Field_2</Text_Field_2>
        <Author>A2</Author>
        <Author>D1</Author>
        <Author>D2</Author>
        <Author>D3</Author>
        <Author>D33</Author>
        <Date>10/12/2019</Date>
        <Summary>Record 1: Summary 1 Text</Summary>
    </Record>
</Data>

Я использовал этот код, но я не уверен, что это правильный путь.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*" />

    <xsl:key name="key" match="Record" use="Key"/>
    <xsl:key name="kNamedSiblings" match="*" 
           use="concat(generate-id(..), '+', name())"/>

    <xsl:template match="*">
      <xsl:copy>
        <xsl:apply-templates select="key('kNamedSiblings', 
                                         concat(generate-id(..), '+', name())
                                        )/node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[not(*) and . = '']" />
    <xsl:template match="*[generate-id() != 
                         generate-id(key('kNamedSiblings', 
                                         concat(generate-id(..), '+', name()))[1]
                                    )]" />
</xsl:stylesheet>

Текущий вывод

<?xml version="1.0"?>
<Data>
  <Record>

    <Key>12345</Key>
    <Number>09095I</Number>
    <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
    <Text_Field_2>This is Text Field 2</Text_Field_2>
    <Author>A1A2A1A2A3A1</Author>
    <Date>10/12/2019</Date>
    <Summary>Record 1: Summary 1 Text</Summary>

    <Key>12345</Key>
    <Number>09095I</Number>
    <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
    <Text_Field_2>This is Text_Field_2</Text_Field_2>
    <Author>A2A1A3B2B2</Author>
    <Date>10/12/2019</Date>
    <Summary>Record 2: Summary 1 Text</Summary>

    <Key>23456</Key>
    <Number>43095I</Number>
    <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
    <Text_Field_2>This is Text_Field_2</Text_Field_2>
    <Author>AA2AA1AA3AA3BB2AA3</Author>
    <Date>01/12/2020</Date>
    <Field_Text_1>This is the Text 1</Field_Text_1>

    <Key>23456</Key>
    <Number>43095I</Number>
    <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
    <Text_Field_2>This is Text_Field_2</Text_Field_2>
    <Author>AA1AA3CC2AA1CC2</Author>
    <Date>01/12/2020</Date>
    <Field_Text_1>This is the Text 1</Field_Text_1>

    <Key>23456</Key>
    <Number>43095I</Number>
    <Text_Field_1>Record 3: This is Text Field 1</Text_Field_1>
    <Text_Field_2>This is Text_Field_2</Text_Field_2>
    <Author>AA1AA3CC2AA1CC3</Author>
    <Date>01/12/2020</Date>
    <Field_Text_1>This is the Text 1</Field_Text_1>

    <Key>778899</Key>
    <Number>998822I</Number>
    <Text_Field_1>Record 1: This is Text_Field_1</Text_Field_1>
    <Text_Field_2>This is Text_Field_2</Text_Field_2>
    <Author>A2A3A3A3</Author>
    <Date>10/12/2019</Date>
    <Field_Text_1>This is the Text 1</Field_Text_1>
  </Record>
</Data>

Мой текущий код создает одну большую запись, а не три отдельные. Кроме того, элементы Author не поддерживаются. Вместо этого создается один элемент, а значения объединяются. Я понимаю, что это поэтапное решение, включающее в себя: - объединение нескольких записей в одну на ключ - удаление пустых тегов - удаление дублирующих тегов с одинаковым значением - сохранение исходной структуры XML

Понимание решение также было бы большой помощью.

Ответы [ 3 ]

2 голосов
/ 29 января 2020

Поскольку ваша таблица стилей показывает, что вы можете использовать XSLT-2.0, вы можете упростить свой подход от использования сложного xsl:key до более простого xsl:for-each-group один:

<xsl:template match="Data">
  <xsl:copy>
    <xsl:for-each-group select="Record" group-by="Key">
      <xsl:copy>
        <xsl:for-each-group select="current-group()/*[normalize-space()]" group-by="concat(name(),.)">
          <xsl:sort select="name()" order="ascending" />
          <xsl:copy-of select="current-group()[1]" />
        </xsl:for-each-group>
      </xsl:copy>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

Этот шаблон группирует элементы Record по Key, а затем группирует его результат по строке, состоящей из имени элемента и его содержимого. Результат сортируется в алфавитном порядке для группировки элементов с одинаковым именем.
Затем выводится первый (и столь уникальный) элемент.

Вывод:

<?xml version="1.0" encoding="UTF-8"?>
<Data>
   <Record>
      <Author>A1</Author>
      <Author>A2</Author>
      <Author>A3</Author>
      <Author>B2</Author>
      <Date>10/12/2019</Date>
      <Key>12345</Key>
      <Number>09095I</Number>
      <Summary>Record 1: Summary 1 Text</Summary>
      <Summary>Record 2: Summary 1 Text</Summary>
      <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
      <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
      <Text_Field_2>This is Text Field 2</Text_Field_2>
      <Text_Field_2>This is Text_Field_2</Text_Field_2>
   </Record>
   <Record>
      <Author>AA2</Author>
      <Author>AA1</Author>
      <Author>AA3</Author>
      <Author>BB2</Author>
      <Author>CC2</Author>
      <Author>CC3</Author>
      <Date>01/12/2020</Date>
      <Key>23456</Key>
      <Number>43095I</Number>
      <Summary>Record 1: Summary 1 Text</Summary>
      <Summary>Record 2: Summary 1 Text</Summary>
      <Summary>Record 3: Summary 1 Text</Summary>
      <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
      <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
      <Text_Field_1>Record 3: This is Text Field 1</Text_Field_1>
      <Text_Field_2>This is Text_Field_2</Text_Field_2>
   </Record>
   <Record>
      <Author>A2</Author>
      <Author>D1</Author>
      <Author>D2</Author>
      <Author>D3</Author>
      <Author>D33</Author>
      <Date>10/12/2019</Date>
      <Key>778899</Key>
      <Number>998822I</Number>
      <Summary>Record 1: Summary 1 Text</Summary>
      <Text_Field_1>Record 1: This is Text_Field_1</Text_Field_1>
      <Text_Field_2>This is Text_Field_2</Text_Field_2>
   </Record>
</Data>
1 голос
/ 29 января 2020

Поскольку у нас уже есть решения XSLT 1 и XSLT 2, для полноты здесь используется решение XSLT 3, использующее xsl:merge:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="Data">
      <xsl:copy>
          <xsl:merge>
              <xsl:merge-source select="Record">
                  <xsl:merge-key select="Key"/>
              </xsl:merge-source>
              <xsl:merge-action>
                  <xsl:copy>
                      <xsl:merge>
                          <xsl:merge-source select="current-merge-group()/*[normalize-space()]" sort-before-merge="yes">
                              <xsl:merge-key select="name()"/>
                              <xsl:merge-key select="."/>
                          </xsl:merge-source>
                          <xsl:merge-action>
                              <xsl:copy-of select="."/>
                          </xsl:merge-action>
                      </xsl:merge>
                  </xsl:copy>
              </xsl:merge-action>
          </xsl:merge>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/gWEaSv5

1 голос
/ 29 января 2020

Помимо хорошего ответа XSLT 2.0 от zx485 , вот таблица стилей XSLT 1.0 с двойной комбинацией клавиш:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*" />
    <xsl:key name="Record-by-Key" match="Record" use="Key"/>
    <xsl:key name="Record-by-Key-child-by-name-value" match="Record/*" 
             use="concat(../Key,'+',name(),'+',.)"/>
    <xsl:template match="Data">
      <Data>
        <xsl:for-each 
             select="*[generate-id()=generate-id(key('Record-by-Key',Key)[1])]">
            <Record>
                <xsl:for-each  
                    select="key('Record-by-Key',Key)
                            /*[generate-id()
                                =generate-id(
                                    key('Record-by-Key-child-by-name-value',
                                        concat(../Key,'+',name(),'+',.))[1])]">
                    <xsl:sort select="name()"/>
                    <xsl:copy-of select="self::*[node()]"/>                
                </xsl:for-each>
            </Record>
        </xsl:for-each>  
      </Data>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<Data>
   <Record>
      <Author>A1</Author>
      <Author>A2</Author>
      <Author>A3</Author>
      <Author>B2</Author>
      <Date>10/12/2019</Date>
      <Key>12345</Key>
      <Number>09095I</Number>
      <Summary>Record 1: Summary 1 Text</Summary>
      <Summary>Record 2: Summary 1 Text</Summary>
      <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
      <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
      <Text_Field_2>This is Text Field 2</Text_Field_2>
      <Text_Field_2>This is Text_Field_2</Text_Field_2>
   </Record>
   <Record>
      <Author>AA2</Author>
      <Author>AA1</Author>
      <Author>AA3</Author>
      <Author>BB2</Author>
      <Author>CC2</Author>
      <Author>CC3</Author>
      <Date>01/12/2020</Date>
      <Key>23456</Key>
      <Number>43095I</Number>
      <Summary>Record 1: Summary 1 Text</Summary>
      <Summary>Record 2: Summary 1 Text</Summary>
      <Summary>Record 3: Summary 1 Text</Summary>
      <Text_Field_1>Record 1: This is Text Field 1</Text_Field_1>
      <Text_Field_1>Record 2: This is Text Field 1</Text_Field_1>
      <Text_Field_1>Record 3: This is Text Field 1</Text_Field_1>
      <Text_Field_2>This is Text_Field_2</Text_Field_2>
   </Record>
   <Record>
      <Author>A2</Author>
      <Author>D1</Author>
      <Author>D2</Author>
      <Author>D3</Author>
      <Author>D33</Author>
      <Date>10/12/2019</Date>
      <Key>778899</Key>
      <Number>998822I</Number>
      <Summary>Record 1: Summary 1 Text</Summary>
      <Text_Field_1>Record 1: This is Text_Field_1</Text_Field_1>
      <Text_Field_2>This is Text_Field_2</Text_Field_2>
   </Record>
</Data>

Приложение: также возможно обеспечить порядок детей по имени ...

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