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>
<note>
<to>Totest</to>
<from>Fromtest</from>
<heading>Query</heading>
<body>Update Windows 10</body>
</note>
<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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></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>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
</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><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:apply-templates select="@*" mode="serialize"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></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>
что также приведет к более надежной сериализации.