XSLT - XML ​​в CDATA

У меня есть mule flow что превращает XML:

HTTP Listener > Logger > XSLT > Logger

Это оригинальное сообщение:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/" xmlns:pref="URI_SOAP_WS">
   <soap:Body>
      <entryXML>
         <note>
            <to>Totest</to>
            <from>Fromtest</from>
            <heading>Query</heading>
            <body>Update Windows 10</body>
         </note>
      </entryXML>
   </soap:Body>
</soap:Envelope>

Я хочу преобразовать с XSLT к этому:

<entryXML>
   &lt;note&gt;
    &lt;to&gt;Totest&lt;/to&gt;
    &lt;from&gt;Fromtest&lt;/from&gt;
    &lt;heading&gt;Query&lt;/heading&gt;
    &lt;body&gt;Update Windows 10&lt;/body&gt;
    &lt;/note&gt;
<entryXML>

Я пробовал с этим шаблоном:

<xsl:stylesheet version="3.0" xmlns:saxon="http://saxon.sf.net/"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:pref="URI_SOAP_WS">

    <xsl:output method="xml" version="1.0" encoding="UTF-8"
        indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="/*">
        <xsl:value-of select="serialize(.)" />
    </xsl:template>

</xsl:stylesheet>

Но это преобразование из <entryXML> в </soap:Envolve>,

Как я могу преобразовать только содержание <entryXML></entryXML>?

1 ответ

Решение

Следующее решение основано на ответе jelovirt, с которым связался Кевин Браун. Вы можете использовать XSLT 3.0 (XPath 3.0) serializeфункция или функция расширения саксонской, которая называется saxon:serialize, но приведенное ниже решение является более переносимым, поскольку оно работает с XSLT 1.0.

Начните с шаблона идентификации, чтобы скопировать все, что не соответствует более конкретному шаблону. В вашем примере это будет соответствовать внешним элементам SOAP.

Тогда сопоставьте entryXML элемент в качестве отправной точки специального режима сериализации. Любой контент внутри entryXML будет обработан в режиме, отличном от режима по умолчанию, и только шаблоны с этим режимом могут быть сопоставлены с вводом.

Таблица стилей XSLT

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="entryXML">
        <xsl:copy>
            <xsl:variable name="nodestring">
                <xsl:apply-templates select="@*|node()" mode="serialize"/>
            </xsl:variable>
            <xsl:value-of select="$nodestring"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*" mode="serialize">
        <xsl:text>&lt;</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
        <xsl:apply-templates mode="serialize"/>
        <xsl:text>&lt;/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
    </xsl:template>

    <xsl:template match="text()" mode="serialize">
        <xsl:value-of select="."/>
    </xsl:template>

</xsl:transform>

Вывод XML

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"
               xmlns:pref="URI_SOAP_WS"
               xmlns:saxon="http://saxon.sf.net/">
   <soap:Body>
      <entryXML>
         &lt;note&gt;
            &lt;to&gt;Tove&lt;/to&gt;
            &lt;from&gt;Jani&lt;/from&gt;
            &lt;heading&gt;Reminder&lt;/heading&gt;
            &lt;body&gt;Don't forget me this weekend!&lt;/body&gt;
         &lt;/note&gt;
      </entryXML>
   </soap:Body>
</soap:Envelope>

РЕДАКТИРОВАТЬ 1

Приведенный выше подход не сериализует атрибуты в сообщении, если они есть. Если вам также необходимо сохранить атрибуты, например, в сообщении типа

<entryXML>
     <note>
        <to with="love">Tove</to>
            ^^^^^^^^^^^               attribute

вам нужно будет добавить шаблон в соответствии с

<xsl:template match="@*" mode="serialize">
    <xsl:text> </xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>="</xsl:text>
    <xsl:value-of select="."/>
    <xsl:text>"</xsl:text>
</xsl:template>

а также изменить шаблон, который соответствует * в serialize Режим:

<xsl:template match="*" mode="serialize">
  <xsl:text>&lt;</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:apply-templates select="@*" mode="serialize"/>
  <xsl:text>&gt;</xsl:text>
  <xsl:apply-templates mode="serialize"/>
  <xsl:text>&lt;/</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>&gt;</xsl:text>
</xsl:template>

РЕДАКТИРОВАТЬ 2

Предостережение. Приведенное выше решение относится только к XSLT 1.0, но оно также имеет недостатки, и нет гарантии, что оно будет правильно сериализовано в каждом возможном случае.

Он работает в простом случае, подобном вашему, но надежная общая сериализация "требует больше усилий", как выразился Мартин Хоннен. Посмотрите, например , таблицу стилей Эвана Ленца для более сложного подхода.

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

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="entryXML/*">
            <xsl:value-of select="serialize(.)" />
    </xsl:template>

</xsl:stylesheet>

что также приведет к более надежной сериализации.

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