Добавление узлов с похожими именами с помощью xslt в wso2

У меня есть некоторые данные xml с несколькими узлами Name. В зависимости от наличия или отсутствия узла id мне нужно разделить узлы. При преобразовании в JSON я хочу, чтобы все похожие узлы были объединены в массив JSON. Ниже приведены мои данные XML

    <Names>
        <CustName>
            <Name>Name1</Name>
            <id>3</id>
        </CustName>
        <CustName >
            <Name>Name2</Name>
        </CustName>
        <CustName>
            <Name>Name3</Name>
            <id>32</id>
        </CustName>
    </Names>

XSLT, который я пробовал, выглядит следующим образом. Но это создает два узла для обновления и один узел для создания. Принимая во внимание, что я хочу, чтобы узлы 1st и 3rd Name находились в узле Update, а узел 2nd Name — в разделе Create

<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
        <xsl:output indent = "no" method = "xml" omit-xml-declaration = "yes"/>
        <xsl:template match = "/">
            <CustomerNames>
                <xsl:for-each select = "//Names/CustName">
                    <xsl:choose>
                        <xsl:when test = "id !=''">
                            <Update>
                                <CustName>
                                    <xsl:value-of select = "Name"/>
                                </CustName>
                                <id>
                                    <xsl:value-of select = "id"/>
                                </id>
                            </Update>
                        </xsl:when>
                        <xsl:otherwise>
                            <Create>
                                <CustName>
                                    <xsl:value-of select = "Name"/>
                                </CustName>
                            </Create>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each>
            </CustomerNames>
        </xsl:template>
    </xsl:stylesheet>


Преобразованный xml должен выглядеть так:

  <CustomerNames>
        <Update>
            <CustName>Name1</CustName>
            <id>3</id>
        </Update>
        <Update>
            <CustName>Name3</CustName>
            <id>32</id>
        </Update>
        <Create>
            <Name>Name2</Name>
        </Create>
    </CustomerNames>


При преобразовании в json я хочу, чтобы аналогичные узлы добавлялись в массив. Так

{
   "CustomerNames":{
      "Update":[
         {
            "CustName":"Name1",
            "id":"3"
         },
         {
            "CustName":"Name3",
            "id":"32"
         }
      ],
      "Create":[
         {
            "Name":"Name2"
         }
      ]
   }
}

Как я могу добиться этого в XSL 1.0?

Ваша таблица стилей создает XML, а не JSON. Пожалуйста, опубликуйте точный ожидаемый результат в формате XML.

michael.hor257k 30.01.2023 14:42

Я не уверен, приведет ли полученный xml к желаемому json. При преобразовании в JSON мне нужен JSONArray, в котором все узлы Name принадлежат либо Update, либо Create.

Ruby 30.01.2023 14:58

Таблица стилей, которую вы уже создали, создает XML, который вы показываете, за исключением порядка узлов Update и Create.

michael.hor257k 30.01.2023 15:04

Да, я знаю, что таблица стилей создает желаемый xml. Но при преобразовании в JSON я получаю 3 разных объекта: 2 для обновления и 1 для создания. Предположим, у меня есть 10 узлов, они будут производить 10 разных объектов. Я хочу 2 JSONArrays для создания и обновления. Update — это массив, состоящий из id, а Create — это массив без id. Можно ли этого добиться с помощью XSLT?

Ruby 30.01.2023 15:10

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

michael.hor257k 30.01.2023 15:20
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
1
5
81
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Кажется, порядок размещения узлов имеет значение при автоматическом преобразовании XML в JSON. Следовательно, обновите свой XSLT до чего-то вроде приведенного ниже.

<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent = "no" method = "xml" omit-xml-declaration = "yes"/>
    <xsl:template match = "/">
        <CustomerNames>
            <xsl:for-each select = "//Names/CustName[id]">
                <Update>
                    <CustName>
                        <xsl:value-of select = "Name"/>
                    </CustName>
                    <id>
                        <xsl:value-of select = "id"/>
                    </id>
                </Update>
            </xsl:for-each>
            <xsl:for-each select = "//Names/CustName[not(id)]">
                <Create>
                    <CustName>
                        <xsl:value-of select = "Name"/>
                    </CustName>
                </Create>
            </xsl:for-each>
        </CustomerNames>
    </xsl:template>
</xsl:stylesheet>

Это работает, спасибо! Но есть ли способ добиться этого, используя один для каждого? Поскольку я заметил, что наличие 2 для каждого здесь увеличивает время отклика только для преобразования xml.

Ruby 30.01.2023 19:38

@Ruby есть разные способы сделать это. Цикл довольно эффективен, поскольку мы не перебираем все элементы в обоих for-each, но всегда есть накладные расходы на обход узла. Я добавил еще один альтернативный подход с одним для каждого. Взгляните на это. Но тем не менее, это будет иметь аналогичные накладные расходы, поскольку дерево XML нуждается в сортировке.

ycr 30.01.2023 20:06

Кроме того, вы можете сгруппировать узлы XML с помощью сортировки XSL.

<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent = "no" method = "xml" omit-xml-declaration = "yes"/>
    <xsl:template match = "/">
        <CustomerNames xmlns = "">
            <xsl:for-each select = "//Names/CustName">
                <xsl:sort select = "id"/>
                <xsl:choose>
                    <xsl:when test = "id !=''">
                        <Update>
                            <CustName>
                                <xsl:value-of select = "Name"/>
                            </CustName>
                            <id>
                                <xsl:value-of select = "id"/>
                            </id>
                        </Update>
                    </xsl:when>
                    <xsl:otherwise>
                        <Create>
                            <CustName>
                                <xsl:value-of select = "Name"/>
                            </CustName>
                        </Create>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </CustomerNames>
    </xsl:template>
</xsl:stylesheet>

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

Ruby 30.01.2023 20:16

@Ruby это решение очень тесно связано с вашим вариантом использования. Просто сортировка элементов Null и Not null.

ycr 30.01.2023 20:25

Другой подход заключается в использовании посредника Payloadfactry после посредника XSLT для группировки узлов. Пример ниже.

<payloadFactory media-type = "xml">
    <format>
        <CustomerNames>
        $1
        $2
        </CustomerNames>
    </format>
    <args>
        <arg expression = "//Update"/>
        <arg expression = "//Create"/>
    </args>
</payloadFactory>

Другие вопросы по теме