XSLT: How to transform partially escaped XML?
I need help transforming an XML file, whose part of it is with escape sequences, into HTML:
<?xml-stylesheet type=text/xsl href=XSL_17.xsl?>
<Root>
<Book>
<Author>John smith</Author>
<Genre>Novel</Genre>
<Details><?xml version="1.0" encoding="utf-16"?><Dets><Ds><D DN="Pages" DV="381" /><D DN="Binding" DV="Hardcover" /><D DN="Rate" DV="7.8" /></Ds></Dets></Details>
</Book>
<Car>
<Year>2010</Year>
<Name>Charger</Name>
<Manufacturer>Dodge</Manufacturer>
</Car>
</Root>
to the following HTML:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></tit开发者_开发知识库le>
</head>
<body>
<table>
<tr>
<td><strong>Book</strong></td>
</tr>
<tr>
<td><strong>Name</strong></td>
<td><strong>Value</strong></td>
</tr>
<tr>
<td>Author</td>
<td>John smith</td>
</tr>
<tr>
<td>Genre</td>
<td>Novel</td>
</tr>
<tr>
<td>Details</td>
<td>
<table>
<tr>
<td><strong>Name</strong></td>
<td><strong>Value</strong></td>
</tr>
<tr>
<td>Pages</td>
<td>381</td>
</tr>
<tr>
<td>Binding</td>
<td>Hardcover</td>
</tr>
<tr>
<td>Rate</td>
<td>7.8</td>
</tr>
</table>
</td>
</tr>
</table>
<table>
<tr>
<td><strong>Car</strong></td>
</tr>
<tr>
<td><strong>Name</strong></td>
<td><strong>Value</strong></td>
</tr>
<tr>
<td>Year</td>
<td>2010</td>
</tr>
<tr>
<td>Name</td>
<td>Charger</td>
</tr>
<tr>
<td>Manufacturer</td>
<td>Dodge</td>
</tr>
</table>
</body>
</html>
I.e., I need to represent both normal XML and escaped XML in HTML tables.
This cannot be done with XSLT unless one implements an XML parser in XSLT.
If you have Saxon, you can use the Saxon extensions saxon:parse()
and saxon:transform()
This XSLT produces the output desired
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output indent="yes"/>
<xsl:template match="/Root">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<xsl:for-each select="*">
<table>
<tr>
<td><strong>
<xsl:value-of select="name()"/>
</strong></td>
</tr>
<tr>
<td><strong>Name</strong></td>
<td><strong>Value</strong></td>
</tr>
<xsl:for-each select="*">
<tr>
<td>
<xsl:value-of select="name()"/>
</td>
<td>
<xsl:choose>
<xsl:when test="current()[not(contains(.,'xml'))]">
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="details"
select="substring-after(.,'?>')"/>
<xsl:variable name="parsedXml_">
<xsl:call-template name="parseXml">
<xsl:with-param name="text" select="$details"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="parsedXml" select="exsl:node-set($parsedXml_)"/>
<table>
<tr>
<td><strong>Name</strong></td>
<td><strong>Value</strong></td>
</tr>
<xsl:for-each select="$parsedXml/Dets/Ds/D">
<tr>
<td>
<xsl:value-of select="@DN"/>
</td>
<td>
<xsl:value-of select="@DV"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template name="parseXml">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '>')">
<xsl:variable name="topLevelTag">
<xsl:call-template name="getTopLevelTag">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="openingTag">
<xsl:value-of select="$topLevelTag"/>
</xsl:variable>
<xsl:variable name="tagName">
<xsl:call-template name="getTopLevelTagName">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="closingTag">
<xsl:value-of select="concat('</',$tagName,'>')"/>
</xsl:variable>
<xsl:variable name="firstNode">
<xsl:if test="not(contains($topLevelTag,'/>'))">
<xsl:value-of select="substring-before(substring-after($text,$openingTag),$closingTag)"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="afterFirstNode">
<xsl:choose>
<xsl:when test="not(contains($topLevelTag,'/>'))">
<xsl:value-of select="substring-after($text,concat($firstNode,$closingTag))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-after($text,$topLevelTag)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$tagName}">
<xsl:call-template name="createAttributes">
<xsl:with-param name="text" select="$topLevelTag"/>
</xsl:call-template>
<xsl:call-template name="parseXml">
<xsl:with-param name="text" select="$firstNode"/>
</xsl:call-template>
</xsl:element>
<xsl:call-template name="parseXml">
<xsl:with-param name="text" select="$afterFirstNode"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="getTopLevelTagName">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '>')">
<xsl:variable name="tagWithAttributesWithoutEnd">
<xsl:value-of select="substring-before($text, '>')"/>
</xsl:variable>
<xsl:variable name="tagWithAttributesWithoutBegining">
<xsl:value-of select="substring-after($tagWithAttributesWithoutEnd, '<')"/>
</xsl:variable>
<xsl:variable name="tagName">
<xsl:choose>
<xsl:when test="contains($tagWithAttributesWithoutBegining,' ')">
<xsl:value-of
select="substring-before($tagWithAttributesWithoutBegining, ' ')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$tagWithAttributesWithoutBegining"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="$tagName"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="getTopLevelTag">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '>')">
<xsl:variable name="tagWithAttributesWithoutEnd">
<xsl:value-of select="substring-before($text, '>')"/>
</xsl:variable>
<xsl:value-of select="concat($tagWithAttributesWithoutEnd,'>')"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="createAttributes">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '="')">
<xsl:variable name="attributeName">
<xsl:value-of select="substring-before(substring-after($text,' '),'="')"/>
</xsl:variable>
<xsl:variable name="attributeValue">
<xsl:value-of select="substring-before(substring-after($text,concat($attributeName,'="')),'"')"/>
</xsl:variable>
<xsl:attribute name="{$attributeName}">
<xsl:value-of select="$attributeValue"/>
</xsl:attribute>
<xsl:call-template name="createAttributes">
<xsl:with-param name="text" select="substring-after($text,concat($attributeName,'="',$attributeValue,'"'))"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
精彩评论