我的XML非常扁平,这是一个例子:
<Rows>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Initiation</Phase>
<ID>1</ID>
<Name>Work item 1</Name>
<Master>1</Master>
</Row>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Initiation</Phase>
<ID>2</ID>
<Name>Work item 2</Name>
<Master>1</Master>
</Row>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Closing</Phase>
<ID>3</ID>
<Name>Work item 3</Name>
<Master>3</Master>
</Row>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Closing</Phase>
<ID>4</ID>
<Name>Work item 4</Name>
<Master>3</Master>
</Row>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Closing</Phase>
<ID>5</ID>
<Name>Work item 5</Name>
<Master>4</Master>
</Row>
</Rows>
它们需要以这样的方式嵌套:
**Initiation**
Work item 1
Work item 2
**Closing**
Work item 3
Work item 4
Work item 5
现在我有一个ProjectID,Phase和Name的模板(作为一个例子,我的实际模板相当大)我开始在ProjectID模板中,按阶段分组和循环,然后按阶段分组和循环-名称。 (所以,我逐个项目得到所有名字的清单)。它仅适用于2个级别(比如工作项目1和2),但第三级(例如工作项目5)已经失去了我。
现在我尝试迭代名称模板中的所有匹配的主字段(其真实代码在此处):
<xsl:template name="Deliverable">
<!--
Parent == True && Lone == True -> Impossible
Parent == True && Lone == False -> Parent
Parent == False && Lone == False -> Child
Parent == False && Lone = True -> Single deliverable -->
<xsl:param name="parent" />
<xsl:param name="lone" />
<xsl:variable name="Parent">
<xsl:choose>
<xsl:when test="count(key('project-phase-deliverables', concat(ProjectNo, '|', Phase, '|', IDField2))) > 1">
1
</xsl:when>
<xsl:otherwise>
0
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="ID"><xsl:value-of select="generate-id(IDField1)" /></xsl:variable>
<tr>
<xsl:choose>
<!-- JS for parent deliverable -->
<xsl:when test="$Parent = 'True'">
<xsl:attribute name="ID">
<xsl:value-of select="$ID"/>
</xsl:attribute>
<script>$('#<xsl:value-of select="$ID"/>').click(function() { $('.<xsl:value-of select="IDField2"/>').toggle(); });</script>
</xsl:when>
<!-- Coloring/attributes for children -->
<xsl:when test="$parent = 'False' and $lone='False'">
<xsl:attribute name="style">background: #DEDEFF; display: none;</xsl:attribute>
<xsl:attribute name="class">
<xsl:value-of select="IDField2"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<td class="doWhite" style="width: 15px; height: 24px; text-align:right; border-right:none;">
<p class="normal">
<!-- Parent deliverable expander arrow -->
<xsl:if test="$Parent = 1">
<span class="Expander">▶</span>
</xsl:if>
</p>
</td>
<td class="doWhite" style="width: 200px; height: 24px; border-left:none;">
<p class="normal">
<!-- Child deliverable diamond -->
<xsl:if test="$parent = 'False' and $lone = 'False'">
<span class="Expander">◆ </span>
</xsl:if>
<xsl:value-of select="ItemDescription"/>
</p>
</td>
<td class="doWhite" style="width: 130px; height: 24px">
<p class="normal">
<xsl:value-of select="Owner"/>
</p>
</td>
<td style="width: 60px; height: 24px">
<xsl:call-template name="status"/>
</td>
<td class="doWhite">
<p class="normal">
<xsl:value-of select="ItemNotes"/>
</p>
</td>
</tr>
<xsl:if test="$Parent = 1">
<xsl:for-each select="key('project-phase-deliverables', concat(ProjectNo, '|', Phase, '|', IDField2))[position()!=1]">
<!-- this doesn't recurse properly :( -->
<xsl:call-template name="Deliverable" />
</xsl:for-each>
</xsl:if>
</xsl:template>
正如你所料,它无限循环并超时。我觉得我可以使用apply-template来解决我的问题但是如何使用它来有效地按其他字段分组(Phase和ProjectID)?
答案 0 :(得分:3)
我可能误解了你的要求,但看起来你可能会在这里过于复杂。
首先,我认为你是阶段。所以设置一个如此的键:
<xsl:key name="Phase" match="Row" use="Phase" />
并匹配每个阶段中最顶层的行,如下所示:
<xsl:apply-templates
select="//Row[generate-id() = generate-id(key('Phase', Phase)[1])]"
mode="first" />
要获取当前行的“子项”,您可以递归调用模板以匹配行元素
<xsl:apply-templates
select="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]" />
因此,给出以下XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="Phase" match="Row" use="Phase"/>
<xsl:template match="/">
<Rows>
<xsl:apply-templates select="//Row[generate-id() = generate-id(key('Phase', Phase)[1])]" mode="first"/>
</Rows>
</xsl:template>
<xsl:template match="Row" mode="first">
<Phase name="{Phase}">
<xsl:apply-templates select="key('Phase', Phase)[Master = ID]"/>
</Phase>
</xsl:template>
<xsl:template match="Row" name="Row">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:apply-templates select="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当应用于您的示例XML时,输出以下内容:
<Rows>
<Phase name="Initiation">
<Row>
<ProjectID>1000</ProjectID>
<Phase>Initiation</Phase>
<ID>1</ID>
<Name>Work item 1</Name>
<Master>1</Master>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Initiation</Phase>
<ID>2</ID>
<Name>Work item 2</Name>
<Master>1</Master>
</Row>
</Row>
</Phase>
<Phase name="Closing">
<Row>
<ProjectID>1000</ProjectID>
<Phase>Closing</Phase>
<ID>3</ID>
<Name>Work item 3</Name>
<Master>3</Master>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Closing</Phase>
<ID>4</ID>
<Name>Work item 4</Name>
<Master>3</Master>
<Row>
<ProjectID>1000</ProjectID>
<Phase>Closing</Phase>
<ID>5</ID>
<Name>Work item 5</Name>
<Master>4</Master>
</Row>
</Row>
</Row>
</Phase>
</Rows>
如果要输出HTML,请尝试以下XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:key name="Phase" match="Row" use="Phase"/>
<xsl:template match="/">
<body>
<xsl:apply-templates select="//Row[generate-id() = generate-id(key('Phase', Phase)[1])]" mode="first"/>
</body>
</xsl:template>
<xsl:template match="Row" mode="first">
<h1>
<xsl:value-of select="Phase"/>
</h1>
<ul>
<xsl:apply-templates select="key('Phase', Phase)[Master = ID]"/>
</ul>
</xsl:template>
<xsl:template match="Row" name="Row">
<li>
<xsl:value-of select="Name"/>
<xsl:if test="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]">
<ul>
<xsl:apply-templates select="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]"/>
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
这应输出以下HTML
<body>
<h1>Initiation</h1>
<ul>
<li>Work item 1
<ul>
<li>Work item 2</li>
</ul>
</li>
</ul>
<h1>Closing</h1>
<ul>
<li>Work item 3
<ul>
<li>Work item 4
<ul>
<li>Work item 5</li>
</ul>
</li>
</ul>
</li>
</ul>
</body>