XSL Transform для динамического генерирования выходного XML из свойств ввода - PullRequest
0 голосов
/ 30 января 2019

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


У меня есть следующие 3 XML-документа (которые служат примерами их структуры):

<?xml version="1.0" encoding="UTF-8" ?>
<rabbitEnvelope>
    <action>YES</action>
    <logId>123</logId>
    <payload class="rabbit">
            <id>1</id>
            <name>Some Bunny</name>
            <easter>false</easter>
    </payload>
</rabbitEnvelope>

<?xml version="1.0" encoding="UTF-8" ?>
<bearEnvelope>
    <action>NO</action>
    <logId>456</logId>
    <payload class="bear">
            <type>Polar</type>
            <weight>655</weight>
    </payload>
</bearEnvelope>

<?xml version="1.0" encoding="UTF-8" ?>
<dogEnvelope>
    <action>MAYBE</action>
    <logId>789</logId>
    <payload class="dog">
            <goodboy>YES!</goodboy>
            <eats>Everything</eats>
        <canFetch>true</canFetch>
        <moniker>Fido</moniker>
    </payload>
</dogEnvelope>

Мы назовем их " классическими версиями " этих 3 различных XMLдокументы.

Мое приложение теперь будет получать " новые версии " из них, и мне нужно написать XSL-преобразование, чтобы преобразовать новые версии в классические.Новые версии (опять же в качестве примеров) этих документов XML будут выглядеть следующим образом:

<?xml version="1.0" encoding="UTF-8" ?>
<envelope>
    <action>YES</action>
    <auditId>123</auditId>
    <payload class="rabbit">
        <id>1</id>
        <name>Some Bunny</name>
        <easter>false</easter>
    </payload>
</envelope>

<?xml version="1.0" encoding="UTF-8" ?>
<envelope>
    <action>NO</action>
    <auditId>456</auditId>
    <payload class="bear">
        <type>Polar</type>
        <weight>655</weight>
    </payload>
</envelope>

<?xml version="1.0" encoding="UTF-8" ?>
<envelope>
    <action>MAYBE</action>
    <auditId>789</auditId>
    <payload class="dog">
        <goodboy>YES!</goodboy>
        <eats>Everything</eats>
        <canFetch>true</canFetch>
        <moniker>Fido</moniker>
    </payload>
</envelope>

Таким образом, в этих "новых версиях" самый внешний элемент XML будет всегда <envelope> элемент.Элемент <action> для новой версии такой же, как и в классической версии.Новый /envelope/auditId такой же, как классический вариант <logId> (/rabbitEnvelope/logId и т. Д.).И /envelope/payload также точно такой же, как и в классической версии (/bearEnvelope/payload и т. Д.).

Итак, еще раз, мне нужно написать XSL-преобразование, которое будет преобразовывать новые версии XML (<envelope> полезные нагрузки) в его классической версии.Как правило:

  • Значение /envelope/payload/@class определяет имя самого внешнего элемента классической версии.Следовательно, это /envelope/payload/@class='rock', тогда внешний / корневой элемент его «классической» версии будет <rockEnvelope>.
  • Я хочу скопировать /envelope/action в /<rootElementEnvelope>/action.Следовательно, если /envelope/action='YES', то /<rootElementEnvelope>/action='YES'.
  • Я хочу скопировать значение из /envelope/auditId в <rootElementEnvelope>/logId.Следовательно, если /envelope/auditId='123', то /<rootElementEnvelope>/logId='123'.
  • Я хочу скопировать весь /envelope/payload в /<rootElementEnvelope>/payload, никаких изменений.

MyПервый удар в общий XSLT выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:template match="//envelope">
    <!-- The rabbitEnvelope element needs to be dynamically generated! -->
    <rabbitEnvelope>
        <action><xsl:value-of select="../action"/></action>
        <logId><xsl:value-of select="../auditId"/></logId>
        <payload class="???">
            <!-- All the XML from inside the source payload tag-->
        </payload>
    </rabbitEnvelope>
</xsl:template>      

Однако здесь есть несколько проблем из-за того же / общего динамического характера моих требований.

  1. Поскольку значение <payload class=???> определяет, является ли преобразованный / результирующий корневой тег <rabbitEnvelope>, <bearEnvelope>, <dogEnvelope>, <rockEnvelope> (или любым другим типом, , и существует МНОГИЕ! ), Я не могу просто жестко кодировать <rabbitEnvelope> в свой XSLT.
  2. Я считаю мое использование <action><xsl:value-of select="../action"/></action> и <logId><xsl:value-of select="../auditId"/></logId> правильно, но если вы видите, что с ним что-то не такПожалуйста, дайте мне знать!
  3. Я не уверен, как сгенерировать выходной / результирующий тег <payload/>, поскольку это просто прямая копия того, что находится во входном XML и не может быть жестко закодировано.

Есть идеи, как мне добиться желаемого преобразования, учитывая динамический характер моих требований здесь? Заранее спасибо!

1 Ответ

0 голосов
/ 30 января 2019

Как насчет:

XSLT 2.0 (также совместим с XSLT 1.0)

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

<xsl:template match="/envelope">
    <xsl:element name="{payload/@class}Envelope">
        <xsl:copy-of select="action"/>
        <logId>
            <xsl:value-of select="auditId"/>
        </logId>
        <xsl:copy-of select="payload"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
...