我正在处理一个下拉菜单,该菜单从Sharepoint列表中提取数据,并使用xsl进行样式设置。 html结构是一个简单的无序列表
<ul><li>parent page</li><ul><li>sub page 1</li><li>sub page2</li></ul></ul>
xsl测试列表中的项目是父页面还是子页面以及子页面编号是什么。父页面有一个数字,因此可以将所需的子页面附加到正确的父页面。
每个项目的基本xsl是:
<xsl:for-each select="//Data/Row">
<xsl:if test="./@Page_x0020_type = 0">
<li >
<a>
<xsl:attribute name="href">
<xsl:value-of
select="./@Page_x002f_link_x0020_url"/>
</xsl:attribute>
<xsl:value-of select="./@Title0"/>
</a>
</li>
</xsl:if>
我希望xsl等于这个: 如果它是子页面,则在项目前面加上ul标签,如果它是父项下的最后一个子页面,则添加一个结束的ul标签。
我如何解决xsl不会让我添加未封闭的ul标签的事实,因为它(正确地)不知道标签是否会被关闭?
XML
<Field Type="Text"
DisplayName="Page/link url"
Required="FALSE"
MaxLength="255"
Name="Page_x002f_link_x0020_url"/>
<Field ReadOnly="TRUE"
Type="Computed"
Name="LinkTitle"
DisplayName="Page number"/>
<Field Type="Text"
DisplayName="Title"
Required="FALSE"
MaxLength="255"
Name="Title0"/>
<Field Type="Choice"
DisplayName="Page type"
Required="FALSE"
Format="RadioButtons"
FillInChoice="FALSE"
Name="Page_x0020_type">
<CHOICES>
<CHOICE>0</CHOICE>
<CHOICE>1</CHOICE>
</CHOICES>
<DefaultFormula>=0</DefaultFormula>
<DefaultFormulaValue/>
</Field>
<Field Type="Text"
DisplayName="Sub page number"
Required="FALSE"
MaxLength="2"
Name="Sub_x0020_page_x0020_number"/>
<Field Type="Text"
DisplayName="Parent page number"
Required="FALSE"
MaxLength="1"
Name="Parent_x0020_page_x0020_number">
<Default>0</Default>
</Field>
</Schema>
<Data ItemCount="1">
<Row Page_x002f_link_x0020_url=""
LinkTitle=""
Title0=""
Page_x0020_type=""
Sub_x0020_page_x0020_number=""
Parent_x0020_page_x0020_number=""
ul=""
_x003c_li_x003e__x003c_a_x003e_=""
_x003c__x002f_a_x003e__x003c__x0=""
_x003c_ul_x003e__x003c_li_x003e_=""
_x003c__x002f_a_x003e__x003c__x00=""
_x003c__x002f_a_x003e__x003c__x01=""/>
<li>parent1</li>
<ul>...<li>sub page 1</li>
<li>sub page #</li>
</ul>
答案 0 :(得分:4)
我希望xsl等同于:如果它是一个子页面,则在项目前面加上ul标签,如果它是父项下的最后一个子页面,则添加一个结束ul标签。
你在想错误的方法。 XSLT不写标签,它写一个节点树。您不能将半个节点写入结果树。
在XSLT 2.0中你可以使用xsl:for-each-group和group-starting-with属性做你想做的事情 - 我不能具体,因为你没有明确指出问题,但它是可能是这样的:
<xsl:template match="parent">
<xsl:for-each-group select="*" group-starting-with="li[....]">
<ul>
<xsl:copy-of select="current-group()"/>
</ul>
</xsl:for-each-group>
</xsl:template>
如果你坚持使用XSLT 1.0,那将会更加困难:我将使用一种名为“兄弟递归”的技术,在这种技术中,你将模板应用于第一个孩子,然后将模板应用于下一个兄弟,等等。父级的模板规则执行此操作:
<xsl:template match="parent">
<xsl:apply-templates select="*[1]"/>
</xsl:template>
作为组中第一个兄弟的模板规则执行此操作:
<xsl:template match="parent/*[ (: where this is the first in a group :) ]">
<group>
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1]"/>
</group>
<xsl:apply-templates select="following-sibling::*[(* start of next group *)][1]"/>
</xsl:template>
以及其他兄弟姐妹的模板规则:
<xsl:template match="parent/*">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1]"/>
</xsl:template>
即使对于有经验的XSLT开发人员来说,细节也很棘手。
答案 1 :(得分:0)
我错过了什么。由于XSL是一个XML文档,可用于将另一个XML(XHTML,SOAP等)文档转换为另一种格式,通常是某种XML。如果将数据文档(字符串等)提供给XSL,它将根据您设置的模式进行转换,该模式必须是有效的XML。
现在,为什么这是您实例中的问题。您是否只构建了结构的一部分,然后将其添加到另一个部分,直到您拥有整个结构?如果是这样,我会将所有位都拉成一段数据(文件,字符串等)并对其进行转换。或者,将占位符保留在最高级别,正确结束标记,并以这种方式添加子位。
看着你的问题,我看到你想要一个有效的和一个无效的,这让我相信你正试图零碎一个解决方案。不幸的是,我知道无法告诉XSL“嘿,这是无效的XML,但不要冒汗”。