当以下兄弟包含 2 child 元素时,XSL XPath 帮助

XSL XPath help when following siblings contain 2 child elements

我在想出一个 XPath 语句时遇到问题,该语句将帮助我从 Excel XML.

创建 table 内容

这是我的基本 Excel XML 结构:

<Table>
<Row>
    <Cell>
        <Data ss:Type="String">Title 1</Data>
    </Cell>
</Row>
<Row>
    <Cell ss:Index="2">
        <Data ss:Type="String">Subtitle1</Data>
    </Cell>
    <Cell>
        <Data ss:Type="String">Filename1</Data>
    </Cell>
</Row>
<Row>
    <Cell ss:Index="2">
        <Data ss:Type="String">Subtitle2</Data>
    </Cell>
    <Cell>
        <Data ss:Type="String">Filename2</Data>
    </Cell>
</Row>
<Row>
    <Cell ss:Index="2">
        <Data ss:Type="String">Subtitle3</Data>
    </Cell>
    <Cell>
        <Data ss:Type="String">Filename3</Data>
    </Cell>
</Row>
<Row>
    <Cell>
        <Data ss:Type="String">Title 2</Data>
    </Cell>
</Row>
<Row>
    <Cell ss:Index="2">
        <Data ss:Type="String">Subtitle1</Data>
    </Cell>
    <Cell>
        <Data ss:Type="String">Filename1</Data>
    </Cell>
</Row>
<Row>
    <Cell ss:Index="2">
        <Data ss:Type="String">Subtitle2</Data>
    </Cell>
    <Cell>
        <Data ss:Type="String">Filename2</Data>
    </Cell>
</Row>
<Row>
    <Cell ss:Index="2">
        <Data ss:Type="String">Subtitle3</Data>
    </Cell>
    <Cell>
        <Data ss:Type="String">Filename3</Data>
    </Cell>
</Row>
<Row>
    <Cell ss:Index="2">
        <Data ss:Type="String">Subtitle4</Data>
    </Cell>
    <Cell>
        <Data ss:Type="String">Filename4</Data>
    </Cell>
</Row>

如上所示,我有两个标题,每个标题都有一个 Cell 元素,我需要能够获取以下包含两个 Cell 元素的同级标题。我需要输出如下所示:

<ul class="nav">
  <li class="sub">
    <a href="javascript:void(0);">Title 1</a>
    <ul>
        <li>
            <a href="javascript:void(0);" data-src="Filename1">Subtitle1</a>
        </li>
        <li>
            <a href="javascript:void(0);" data-src="Filename2">Subtitle2</a>
        </li>
        <li>
            <a href="javascript:void(0);" data-src="Filename3">Subtitle3</a>
        </li>
    </ul>
  </li>
  <li class="sub">
    <a href="javascript:void(0);">Title 2</a>
    <ul>
        <li>
            <a href="javascript:void(0);" data-src="Filename1">Subtitle1</a>
        </li>
        <li>
            <a href="javascript:void(0);" data-src="Filename2">Subtitle2</a>
        </li>
        <li>
            <a href="javascript:void(0);" data-src="Filename3">Subtitle3</a>
        </li>
        <li>
            <a href="javascript:void(0);" data-src="Filename4">Subtitle4</a>
        </li>
    </ul>
  </li>
</ul>

我会提供一些代码,但恐怕我还没有走得太远。我是 XSLT 的菜鸟。

XSLT 1.0 解决方案

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output indent="yes"/>

    <xsl:template match="Table">
        <ul class="nav">
            <xsl:apply-templates select="Row[count(Cell)=1]"/>
        </ul>
    </xsl:template>

    <xsl:template match="Row[count(Cell)=1]">
        <li class="sub">
            <a href="javascript:void(0);"><xsl:value-of select="Cell/Data"/></a>
            <ul>
                <xsl:variable name="heading" select="."/>
                <xsl:apply-templates 
                      select="following-sibling::Row[Cell[2]]
                                [generate-id(preceding-sibling::Row[count(Cell)=1][1]) = 
                                                 generate-id($heading)]"/>
            </ul>
        </li>
    </xsl:template>

    <xsl:template match="Row[Cell[2]]">
        <li>
            <a href="javascript:void(0);" data-src="{ Cell[2]/Data }">
              <xsl:value-of select="Cell[1]/Data"/>
            </a>
        </li>
    </xsl:template>
</xsl:stylesheet>

这是另一种方式(复制了 Mads Hansen 的回答)使用 xsl:key:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes" method="xml"/>

    <xsl:key name="element" match="Row[Cell[2]]" use="generate-id(preceding::Row[count(Cell) = 1][1])"/>

    <xsl:template match="Table">
        <ul class="nav">
            <xsl:apply-templates select="Row[count(Cell)=1]"/>
        </ul>
    </xsl:template>

    <xsl:template match="Row[count(Cell)=1]">
        <li class="sub">
            <a href="javascript:void(0);">
                <xsl:value-of select="Cell/Data"/>
            </a>
            <ul>
                <xsl:apply-templates  select="key('element', generate-id())"/>
            </ul>
        </li>
    </xsl:template>

    <xsl:template match="Row[Cell[2]]">
        <li>
            <a href="javascript:void(0);" data-src="{ Cell[2]/Data }">
                <xsl:value-of select="Cell[1]/Data"/>
            </a>
        </li>
    </xsl:template>

</xsl:stylesheet>