好的,继续我的问题here。
让我们说我的网页现在是这样的:
<page>
<header>Page A</header>
<content-a>Random content for page A</content-a>
<content-b>More of page A's content</content-b>
<content-c>More of page A's content</content-c>
<!-- This doesn't keep going: there are a predefined number of sections -->
</page>
<page include="A.xml">
<header>Page B</header>
<content-a>Random content for page B</content-a>
<content-b>More of page B's content</content-b>
<content-c>More of page B's content</content-c>
</page>
<page include="B.xml">
<header>Page C</header>
<content-a>Random content for page C</content-a>
<content-b>More of page C's content</content-b>
<content-c>More of page C's content</content-c>
</page>
转换后(C.xml
),我想结束这个:
<h1>Page C</h1>
<div>
<p>Random content for page C</p>
<p>Random content for page B</p>
<p>Random content for page A</p>
</div>
<div>
<p>More of page C's content</p>
<p>More of page B's content</p>
<p>More of page A's content</p>
</div>
<div>
<p>Yet more of page C's content</p>
<p>Yet more of page B's content</p>
<p>Yet more of page A's content</p>
</div>
我知道我可以使用document(@include)
来包含其他文档。但是,递归有点超出我的范围。
我将如何编写这样的转换?
答案 0 :(得分:2)
这是一个XSLT 2.0解决方案:
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="page">
<xsl:variable name="pages">
<xsl:apply-templates select="." mode="load" />
</xsl:variable>
<xsl:copy>
<h1><xsl:value-of select="header" /></h1>
<!-- you say there is a fixed number of names, so this should be OK -->
<xsl:for-each select="'content-a','content-b','content-c'">
<div>
<xsl:apply-templates select="$pages/page/*[name() = current()]" />
</div>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="page" mode="load">
<xsl:sequence select="." />
<xsl:apply-templates select="document(@include)" mode="load" />
</xsl:template>
<xsl:template match="content-a|content-b|content-c">
<p><xsl:value-of select="." /></p>
</xsl:template>
</xsl:stylesheet>
编辑:对于XSLT 1.0,等效的解决方案如下所示:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
>
<xsl:template match="page">
<xsl:variable name="pages-rtf"><!-- rtf = result tree fragment -->
<xsl:apply-templates select="." mode="load" />
</xsl:variable>
<xsl:variable name="pages" select="exsl:node-set($pages-rtf)" />
<!-- you say there is a fixed number of names, so this should be OK -->
<xsl:variable name="nodes-rtf">
<content-a/><content-b/><content-c/>
</xsl:variable>
<xsl:variable name="nodes" select="exsl:node-set($nodes-rtf)" />
<xsl:copy>
<h1><xsl:value-of select="header" /></h1>
<xsl:for-each select="$nodes">
<div>
<xsl:apply-templates select="$pages/page/*[name() = name(current())]" />
</div>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="page" mode="load">
<xsl:copy-of select="." />
<xsl:apply-templates select="document(@include)" mode="load" />
</xsl:template>
<xsl:template match="content-a|content-b|content-c">
<p><xsl:value-of select="." /></p>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="page">
<h1>
<xsl:value-of select="header"/>
</h1>
<div>
<xsl:apply-templates select="." mode="content-a"/>
</div>
<div>
<xsl:apply-templates select="." mode="content-b"/>
</div>
<div>
<xsl:apply-templates select="." mode="content-c"/>
</div>
</xsl:template>
<xsl:template match="page" mode="content-a">
<p><xsl:value-of select="content-a"/></p>
<xsl:if test="@include">
<xsl:apply-templates select="document(@include)" mode="content-a"/>
</xsl:if>
</xsl:template>
<xsl:template match="page" mode="content-b">
<p><xsl:value-of select="content-b"/></p>
<xsl:if test="@include">
<xsl:apply-templates select="document(@include)" mode="content-b"/>
</xsl:if>
</xsl:template>
<xsl:template match="page" mode="content-c">
<p><xsl:value-of select="content-c"/></p>
<xsl:if test="@include">
<xsl:apply-templates select="document(@include)" mode="content-c"/>
</xsl:if>
</xsl:template>
<xsl:template match="page" mode="header">
<xsl:value-of select="header"/>
<xsl:if test="@include">
<xsl:apply-templates select="document(@include)" mode="header"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:-1)
这是我提出的解决方案。这个只加载每个子页面一次,而不是每个内容加载一次:
<xsl:template match="content-a | content-b | content-c">
<p><xsl:value-of select="."></p>
</xsl:template>
<xsl:template name="get-content">
<xsl:param name='page' />
<xsl:param name='content-a' />
<xsl:param name='content-b' />
<xsl:param name='content-c' />
<xsl:choose>
<xsl:when test="$page/@include">
<xsl:for-each select="document($page/@include)/page"> <!--set context-->
<xsl:call-template name="get-members">
<xsl:with-param name="content-a" select="$content-a | content-a" />
<xsl:with-param name="content-b" select="$content-b | content-b" />
<xsl:with-param name="content-c" select="$content-c | content-c" />
</xsl:call-template>
</xsl:xsl:for-each>
</xsl:when>
<xsl:otherwise>
<div>
<xsl:apply-templates select="$content-a" />
</div>
<div>
<xsl:apply-templates select="$content-b" />
</div>
<div>
<xsl:apply-templates select="$content-c" />
</div>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="page">
<h1><xsl:value-of select="header"></h1>
<xsl:call-template name="get-members">
<xsl:with-param name="content-a" select="content-a" />
<xsl:with-param name="content-b" select="content-b" />
<xsl:with-param name="content-c" select="content-c" />
</xsl:call-template>
</xsl:template>
这是否比其他解决方案更好或更差?