Денормализация XML с использованием XSLT 2.0
Я пытаюсь денормализовать XML с помощью XSLT 2.0.
Ниже приведен XML и ожидаемый результат того же. Будет очень полезно, если кто-то может предоставить XSLT для этого. Денормализация должна работать только для тегов, начинающихся с "Изменить", а не для других тегов. Другие теги должны оставаться как есть.
Образец входного XML
<p> This is normal text
<changebold>This is new line</changebold>
My Name is
<table>
<tr>
<td>FirstName</td>
<td>LastName</td>
<td>Testing for <changebold>Bold <changeitalic>Italic <changeunderline>UnderLine</changeunderline>
</changeitalic>
</changebold>
</td>
</tr>
</table>
<changebold>The Test <changeitalic>of Chemistry<changeunderline>is passed</changeunderline>
</changeitalic> and for biology <changeunderline>the result</changeunderline> is unknown <changeunderline> and under process.</changeunderline>
<changeitalic>The result</changeitalic> of same<changeunderline>will be</changeunderline> displayed on <changeitalic>noticeboard soon.</changeitalic>
</changebold>
<table>table heading <tr>Row <td>Cell1</td>Row End</tr>Table Heading end. </table>
</p>
Ожидаемый вывод сверху XML
<p> This is normal text
<changebold>This is new line</changebold>
My Name is
<table>
<tr>
<td>FirstName</td>
<td>LastName</td>
<td>Testing for <changebold>Bold </changebold>
<changebold>
<changeitalic>Italic</changeitalic>
</changebold>
<changebold>
<changeitalic>
<changeunderline>UnderLine</changeunderline>
</changeitalic>
</changebold>
</td>
</tr>
</table>
<changebold>The Test </changebold>
<changebold>
<changeitalic>of Chemistry</changeitalic>
</changebold>
<changebold>
<changeitalic>
<changeunderline>is passed</changeunderline>
</changeitalic>
</changebold>
<changebold> and for biology </changebold>
<changebold>
<changeunderline>the result</changeunderline>
</changebold>
<changebold> is unknown </changebold>
<changebold>
<changeunderline> and under process.</changeunderline>
</changebold>
<changebold>
<changeitalic>The result</changeitalic>
</changebold>
<changebold> of same</changebold>
<changebold>
<changeunderline>will be</changeunderline>
</changebold>
<changebold> displayed on </changebold>
<changebold>
<changeitalic>noticeboard soon.</changeitalic>
</changebold>
<table>table heading <tr>Row <td>Cell1</td>Row End</tr>Table Heading end. </table>
</p>
1 ответ
Посмотрите на этот XSLT, который способен выдавать желаемый результат:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="(node() | @*)"/>
</xsl:copy>
</xsl:template>
<!--To check if element starts with change and has some child element with the name of change -->
<xsl:template
match="*[starts-with(name(self::*), 'change') and child::*[starts-with(name(self::*), 'change')]]">
<xsl:call-template name="checkNode">
<xsl:with-param name="element" select="self::*"/>
</xsl:call-template>
</xsl:template>
<!-- This checkNode is producing almost 90% result but it fails when we have <changebold>Bold <changeitalic>Italic <changeunderline>UnderLine</changeunderline>
it is producing result like:
<changebold>
<changeitalic>Italic </changeitalic>
<changeitalic>
<changeunderline>UnderLine</changeunderline>
</changeitalic>
</changebold>
-->
<xsl:template name="checkNode">
<xsl:param name="element"/>
<xsl:param name="nesting">
<xsl:for-each select="$element/node()">
<xsl:element name="{self::node()/parent::node()/name()}">
<xsl:apply-templates select="."/>
</xsl:element>
</xsl:for-each>
</xsl:param>
<xsl:for-each select="$nesting/child::*">
<xsl:choose>
<xsl:when test="count(self::*/child::*) gt 1">
<xsl:call-template name="getChild">
<xsl:with-param name="element" select="self::*"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- Here, we are iterating again to get the desired result which was not done by previous 'checkNode' template-->
<xsl:template name="getChild">
<xsl:param name="element"/>
<xsl:param name="start" select="xs:integer(1)"/>
<xsl:param name="countChild" select="count($element/child::*)"/>
<xsl:choose>
<xsl:when test="$start le $countChild">
<xsl:element name="{self::*/name()}">
<xsl:copy-of select="child::*[$start]"/>
</xsl:element>
<xsl:call-template name="getChild">
<xsl:with-param name="element" select="$element"/>
<xsl:with-param name="countChild" select="$countChild"/>
<xsl:with-param name="start" select="$start + 1"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>