XSLT - how to parse xml with recursive elements to Eclipse toc.xml?
I have the following XML:
<HTML>
<HEAD>
<META name="GENERATOR" content="Microsoft HTML Help Workshop 4.1" />
<!-- Sitemap 1.0 -->
</HEAD>
<BODY>
<OBJECT type="text/site properties">
<param name="FrameName" value="contents" />
</OBJECT>
<UL>
<LI>
<OBJECT type="text/sitemap">
<param name="Name" value="Title1" />
<param name="Local" value="Ref1" />
</OBJECT>
<UL>
<LI>
<OBJECT type="text/sitemap">
<param name="Name" value="Title 2" />
<param name="Local" value="Ref2" />
</OBJECT>
<UL>
<LI>
<OBJECT type="text/sitemap">
<param name="Name" value="Title3" />
<param name="Local" value="Ref3" />
</OBJECT>
</LI>
<LI>
<OBJECT type="text/sitemap">
<param name="Name" value="Title4" />
<param name="Local" value="Ref4" />
</OBJECT>
</LI>
</UL>
</LI>
<LI>
<OBJECT type="text/sitemap">
<param name="Name" value="Title5" />
<param name="Local" value="Ref5" />
</OBJECT>
</LI>
</UL>
</LI>
<LI>
<OBJECT type="text/sitemap">
<param name="Name" value="Title6" />
<param name="Local" value="Ref6" />
</OBJECT>
</LI>
</UL>
</BODY>
</HTML>
I need to transform it to an "Eclipse Help" format toc.xml
file, like this:
<toc label="Sample Tab开发者_StackOverflow社区le of Contents">
<topic label="Title1" href="Ref1">
<topic label="Title2" href="Ref2">
<topic label="Title3" href="Ref3"/>
<topic label="Title4" href="Ref4"/>
</topic>
<topic label="Title5" href="Ref5">
</topic>
</topic>
<topic label="Title6" href="Ref6"/>
</toc>
I tried to create the following XSLT, which didn't work:
<?xml version="1.0" encoding="utf-8"?>
<?altova_samplexml D:\Documents and Settings\oshecht\Desktop\XSL\Copy of toc.xml?>
<xsl:stylesheet
version="1.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="/">
<toc>
<xsl:apply-templates select="//LI" />
</toc>
</xsl:template>
<xsl:template match="//LI">
<topic>
<xsl:apply-templates select="OBJECT/param" mode="val" />
<xsl:apply-templates select="OBJECT/param" mode="ref" />
<xsl:apply-templates select="/UL/LI" />
<!--xsl:apply-templates select="//UL//LI" mode="subelement" /-->
</topic>
</xsl:template>
<xsl:template match="OBJECT/param" mode="val">
<xsl:if test="@name = 'Name'">
<xsl:attribute name="label">
<xsl:value-of select="@value" />
</xsl:attribute>
</xsl:if>
</xsl:template>
<xsl:template match="OBJECT/param" mode="ref">
<xsl:if test="@name = 'Local'">
<xsl:attribute name="href">
<xsl:value-of select="@value" />
</xsl:attribute>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Can you please advise?
Thanks:)
I think the following does what you want:
<xsl:template match="BODY">
<toc label="Sample Table of Contents">
<xsl:apply-templates select="UL/LI/OBJECT"/>
</toc>
</xsl:template>
<xsl:template match="OBJECT">
<topic label="{param[@name='Name']/@value}" href="{param[@name='Local']/@value}">
<xsl:apply-templates select="following-sibling::UL/LI/OBJECT"/>
</topic>
</xsl:template>
Your main problem is this line:
<xsl:apply-templates select="//LI" />
This produces a list of all <LI>
elements in the input, and thus creates a flat output list. You can use the built-in recursion and "move with the flow", like this:
<xsl:stylesheet
version="1.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="BODY">
<toc>
<xsl:apply-templates select="OBJECT" />
<xsl:apply-templates select="UL" />
</toc>
</xsl:template>
<xsl:template match="UL">
<xsl:apply-templates select="LI" />
</xsl:template>
<xsl:template match="LI">
<topic>
<xsl:apply-templates select="OBJECT" />
<xsl:apply-templates select="UL" />
</topic>
</xsl:template>
<xsl:template match="OBJECT">
<xsl:apply-templates select="param" />
</xsl:template>
<xsl:template match="OBJECT/param">
<xsl:variable name="attrName">
<xsl:choose>
<xsl:when test="@name = 'FrameName'">label</xsl:when>
<xsl:when test="@name = 'Name'">label</xsl:when>
<xsl:when test="@name = 'Local'">href</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:if test="$attrName != ''">
<xsl:attribute name="{$attrName}">
<xsl:value-of select="@value" />
</xsl:attribute>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The output produced is:
<?xml version="1.0" encoding="utf-8"?>
<toc label="contents">
<topic label="Title1" href="Ref1">
<topic label="Title 2" href="Ref2">
<topic label="Title3" href="Ref3"></topic>
<topic label="Title4" href="Ref4"></topic>
</topic>
<topic label="Title5" href="Ref5"></topic>
</topic>
<topic label="Title6" href="Ref6"></topic>
</toc>
Note that I replaced your "mode" templates whith an <xsl:choose>
. The rest is fairly obvious, I think.
精彩评论