генерация динамического xml с использованием XSLT

У нас есть входящие данные JSON из источника, которые содержат данные и столбец в одной полезной нагрузке. Используя json-to-xml в XSLT, я смог сгенерировать XML следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
   <boolean key="allData">true</boolean>
   <map key="factMap">
      <map key="T!T">
         <array key="rows">
            <map>
               <array key="dataCells">
                  <map>
                     <string key="label">1A</string>
                     <string key="value">1A</string>
                  </map>
                  <map>
                     <string key="label">1B</string>
                     <string key="value">1B</string>
                  </map>
                  <map>
                     <string key="label">1C</string>
                     <string key="value">1C</string>
                  </map>
               </array>
            </map>
            <map>
               <array key="dataCells">
                  <map>
                     <string key="label">2A</string>
                     <string key="value">2A</string>
                  </map>
                  <map>
                     <string key="label">2B</string>
                     <string key="value">2B</string>
                  </map>
                  <map>
                     <string key="label">2C</string>
                     <string key="value">2C</string>
                  </map>
               </array>
            </map>
            <map>
               <array key="dataCells">
                  <map>
                     <string key="label">3A</string>
                     <string key="value">3A</string>
                  </map>
                  <map>
                     <string key="label">3B</string>
                     <string key="value">3B</string>
                  </map>
                  <map>
                     <string key="label">3C</string>
                     <string key="value">3C</string>
                  </map>
               </array>
            </map>
         </array>
      </map>
   </map>
   <map key="detailColumnInfo">
      <map key="Product_vod__c.F1">
         <string key="dataType">string</string>
         <string key="label">F1</string>
      </map>
      <map key="Product_vod__c.F2">
         <string key="dataType">string</string>
         <string key="label">F2</string>
      </map>
      <map key="Product_vod__c.F3">
         <string key="dataType">string</string>
         <string key="label">F3</string>
      </map>
   </map>
</map>

Здесь каждая строка доступна под тегом dataCells как метка и значение. Значение в dataCells представляет значение поля, однако метка не представляет имя поля. Имена полей и порядок полей являются частью тега detailColumnInfo. Порядок и количество полей / данных не фиксированы, однако целевой XML должен оставаться фиксированным. Например. входящие данные могут иметь 10 полей и данные в любом порядке, однако целевой XML должен иметь только 2 поля. Чтобы реализовать это, я считаю, что во время выполнения мы должны выяснить порядок поля F1 и выбрать соответствующие данные из dataCells. Например. если F1 - это первое поле в detailColumnInfo, тогда мне нужно выбрать первое значение из всех ячеек данных (1A, 2A, 3A) и сгенерировать целевой XML со значением поля F1 и так далее.

Тег Detailcolumninfo представляет сведения о столбце. Положение поля значения в Detailcolumninfo будет определять положение полей в Datacells. Для фрагмента кода ввода, опубликованного в запросе, если F1 является 1-й меткой в ​​Detailcolumninfo, тогда первое значение в Datacells (1A, 2A, 3A) представляет значение F1. Аналогично 1B, 2B, 3B представляют значение F2. Целевой XML должен выглядеть следующим образом:

<Root>   
<Rows> 
<Row> 
<F1> 1A </F1> 
<F2> 1B </F2> 
<F3> 1C </F3> 
</Row> 
<Row> 
<F1>2A </F1> 
<F2> 2B </F2> 
<F3> 2C </F3> 
</Row> 
<Row> 
<F1>3A </F1> 
<F2> 3B </F2> 
<F3> 3C </F3> 
</Row> 
</Rows> 

Can anyone suggest possible solutions to implement such dynamic mapping.


person Malay Ruparel    schedule 08.11.2017    source источник
comment
Я не понял, что определяет связь между столбцами и полями и порядок. Число, например, в Fx индикатор позиции? Как результат XML будет выглядеть для отправленного вами входного фрагмента? Как это будет отличаться для другого входного фрагмента?   -  person Martin Honnen    schedule 08.11.2017
comment
Я хотел бы помочь, но я действительно не смог разобраться в основных принципах проблемы: каков ваш ввод, каков ваш текущий вывод, каков ваш ожидаемый результат, какой код дает неправильный вывод ?   -  person Michael Kay    schedule 08.11.2017
comment
Тег Detailcolumninfo представляет сведения о столбце. Положение поля значения в Detailcolumninfo будет определять положение полей в Datacells. Для фрагмента кода ввода, опубликованного в запросе, если F1 является 1-й меткой в ​​Detailcolumninfo, тогда первое значение в Datacells (1A, 2A, 3A) представляет значение F1. Аналогично 1B, 2B, 3B представляют значение F2. Целевой XML-файл должен выглядеть следующим образом: ‹Root› ‹Rows› ‹Row› ‹F1› 1A ‹/F1› ‹F2› 1B ‹/F1› ‹F3› 1C ‹/F3› ‹/Row› ‹Row› ‹F1› 2A ‹/F1› ‹F2› 2B ‹/F1› ‹F3› 2C ‹/F3› ‹/Row› ‹Row› ‹F1› 3A ‹/F1› ‹F2› 3B ‹/F1› ‹F3› 3C ‹/ F3 ›‹/Row› ‹/Rows› ‹/Root›   -  person Malay Ruparel    schedule 08.11.2017
comment
Измените вопрос и предоставьте код в виде хорошо отформатированных фрагментов кода.   -  person Martin Honnen    schedule 08.11.2017
comment
По-прежнему трудно понять, учитывая неверно сформированные примеры, такие как <F2> 1B </F1>. Вы просто хотите сопоставить первый array key="dataCells" с первым Row, второй со вторым Row, но каждый будет брать имена элементов из элемента map key="detailColumnInfo"? Или 1 в F1 также каким-то образом является индексом для доступа к строкам?   -  person Martin Honnen    schedule 08.11.2017
comment
Я отредактировал и исправил вывод. Под ключом = «detailColumnInfo» значение каждого ‹map› представляет каждое поле. Под такой картой метка представляет собой название поля. F1 - это первое поле, а соответствующие данные этого поля - это первая карта для всех ячеек данных, то есть 1A, 2A и 3A. F2 - это 2-е поле, а соответствующие данные этого поля - 2-я карта для всех ячеек данных, то есть 1B, 2B и 3B. Подводя итоги, можно сказать, что информация о столбце определяет 2 аспекта, а именно: положение поля и имя поля. Позиция поля используется для извлечения одинаковых значений позиции из ячеек данных, а имя поля используется для создания имен тегов в целевом XML.   -  person Malay Ruparel    schedule 09.11.2017
comment
Я думаю, что мой опубликованный ответ дает желаемый результат.   -  person Martin Honnen    schedule 09.11.2017
comment
Работал для большинства данных, но для небольшого количества входящих данных возникла следующая ситуация: Если значение поля равно нулю, то входящие данные: ‹map› ‹строковый ключ = метка› 1A ‹/string› ‹строковый ключ = значение› 1A ‹/string› ‹/ карта ›‹map›‹ строковый ключ = метка ›1B ‹/string›‹ нулевой ключ = значение / ›‹/map› ‹map›‹ строковый ключ = метка ›1C ‹/string›‹ строковый ключ = значение ›1C‹ / строка ›‹/map› ‹/array› ‹/map› Скрипт шифрует следующие значения: ‹Rows› ‹Row› ‹F1› 1A ‹/F1› ‹F2› 1C ‹/F2› ‹/Row› Значение F3 копируется в F2, а тег F3 пропускается. Ожидаемая операция ‹Row› ‹F1› 1A ‹/F1› ‹F2 /› ‹F3› 1C ‹/F3› ‹/Row› Можно и пп. предложить   -  person Malay Ruparel    schedule 13.11.2017


Ответы (1)


Вот пример, который предполагает, что вы просто хотите сопоставить каждый элемент array с key="dataCells" с элементом Row, а затем вывести его потомков string с key="value", заключенными в метку из detailColumnInfo:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 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"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math fn"
    expand-text="yes"
    version="3.0">

    <xsl:param name="json-xml">
        <map xmlns="http://www.w3.org/2005/xpath-functions">
            <boolean key="allData">true</boolean>
            <map key="factMap">
                <map key="T!T">
                    <array key="rows">
                        <map>
                            <array key="dataCells">
                                <map>
                                    <string key="label">1A</string>
                                    <string key="value">1A</string>
                                </map>
                                <map>
                                    <string key="label">1B</string>
                                    <string key="value">1B</string>
                                </map>
                                <map>
                                    <string key="label">1C</string>
                                    <string key="value">1C</string>
                                </map>
                            </array>
                        </map>
                        <map>
                            <array key="dataCells">
                                <map>
                                    <string key="label">2A</string>
                                    <string key="value">2A</string>
                                </map>
                                <map>
                                    <string key="label">2B</string>
                                    <string key="value">2B</string>
                                </map>
                                <map>
                                    <string key="label">2C</string>
                                    <string key="value">2C</string>
                                </map>
                            </array>
                        </map>
                        <map>
                            <array key="dataCells">
                                <map>
                                    <string key="label">3A</string>
                                    <string key="value">3A</string>
                                </map>
                                <map>
                                    <string key="label">3B</string>
                                    <string key="value">3B</string>
                                </map>
                                <map>
                                    <string key="label">3C</string>
                                    <string key="value">3C</string>
                                </map>
                            </array>
                        </map>
                    </array>
                </map>
            </map>
            <map key="detailColumnInfo">
                <map key="Product_vod__c.F1">
                    <string key="dataType">string</string>
                    <string key="label">F1</string>
                </map>
                <map key="Product_vod__c.F2">
                    <string key="dataType">string</string>
                    <string key="label">F2</string>
                </map>
                <map key="Product_vod__c.F3">
                    <string key="dataType">string</string>
                    <string key="label">F3</string>
                </map>
            </map>
        </map>
    </xsl:param>

    <xsl:variable name="label-names" as="xs:string*" select="$json-xml//fn:map[@key = 'detailColumnInfo']/fn:map/fn:string[@key = 'label']/string()"/>

    <xsl:output indent="yes"/>

    <xsl:template match="/" name="xsl:initial-template">
        <xsl:apply-templates select="$json-xml//fn:map[@key = 'factMap']"/>
    </xsl:template>

    <xsl:template match="fn:map[@key = 'factMap']">
        <Root>
            <Rows>
                <xsl:apply-templates select="$json-xml//fn:array[@key = 'rows']/fn:map/fn:array"/>
            </Rows>
        </Root>
    </xsl:template>

    <xsl:template match="fn:array[@key = 'rows']/fn:map/fn:array">
        <Row>
            <xsl:apply-templates select="fn:map/fn:string[@key = 'value']"/>    
        </Row>
    </xsl:template>

    <xsl:template match="fn:string[@key = 'value']">
        <xsl:element name="{let $pos := position() return $label-names[$pos]}">{.}</xsl:element>
    </xsl:template>

</xsl:stylesheet>

Выход

<Root>
   <Rows>
      <Row>
         <F1>1A</F1>
         <F2>1B</F2>
         <F3>1C</F3>
      </Row>
      <Row>
         <F1>2A</F1>
         <F2>2B</F2>
         <F3>2C</F3>
      </Row>
      <Row>
         <F1>3A</F1>
         <F2>3B</F2>
         <F3>3C</F3>
      </Row>
   </Rows>
</Root>
person Martin Honnen    schedule 08.11.2017