XSLT 包含两个句点

Posted

技术标签:

【中文标题】XSLT 包含两个句点【英文标题】:XSLT contains two periods 【发布时间】:2011-05-26 18:21:12 【问题描述】:

我有一个使用无序列表显示导航的 html 文档。当它作为 XML 输出时,它不再使用列表,而是为每个链接分配一个<Description>。描述的工作方式是为主链接分配数字,如 100、200、300、400 等。这些子导航链接分配如下:200.100、200.200、200.300 等。

XML 如下所示:

<Items>
  <PgIndexElementItem>
      <Description>100</Description>
      <Title>This is the Title</Title>
  </PgIndexElementItem>
  <PgIndexElementItem>
      <Description>200</Description>
      <Title>This is the Title</Title>
  </PgIndexElementItem>
  <PgIndexElementItem>
      <Description>200.100</Description>
      <Title>This is the Title</Title>
  </PgIndexElementItem>
  <PgIndexElementItem>
      <Description>200.100.100</Description>
      <Title>This is the Title</Title>
  </PgIndexElementItem>
</Items>

如果你看最后一个 PgIndexElementItem,有三组数字。

我正在尝试使用 XSLT 重新创建无序列表。这是我迄今为止一直在做的事情:

<ul>
    <xsl:for-each select="//PgIndexElementItem">
        <xsl:if test="not(contains(Description, '.'))">
            <li><a href="ResolvedURL/ServerRelative"><xsl:value-of select="Title"/></a>
                <ul>
                    <xsl:for-each select="//PgIndexElementItem">
                        <xsl:if test="contains(Description, '.')">
                            <li><a href="ResolvedURL/ServerRelative"><xsl:value-of select="Title"/></a></li>
                        </xsl:if>
                    </xsl:for-each>
                </ul>
            </li>
        </xsl:if>
    </xsl:for-each>
</ul>

我的问题是,有没有办法指定 contains(Description 以两个句点为目标的描述,例如上面最后一个 PgIndexElementItem?

我希望我解释得足够好。我不知道如何使它不那么混乱。提前致谢!

编辑

o Graduate Program
   * How to Apply
   * Masters Program
        o M.A. Handbook
        o FAQs
        o Alumni
        o Masters Theses
        o Sample Thesis Proposals
   * M.A. Handbook
   * FAQs
   * Alumni
   * Masters Theses
   * Sample Thesis Proposals

【问题讨论】:

你的解析器支持 xpath 2 还是 xslt 2? 不确定。我怎么会发现呢?抱歉,有了这些东西的全新世界。 @jrottier,您使用什么技术运行此代码? 您的 XML 需要一个***元素,即 PgIndexElementItem 元素的父元素。例如。用&lt;root&gt;...&lt;/root&gt;包围整个事情。 有一个 &lt;Items&gt; 元素围绕着所有 PgIndexElementItem 元素。上面还有很多,但为了简单起见,我没有列出它们。 【参考方案1】:

你可以使用

<xsl:if test="contains(substring-after(Description, '.'), '.')">
    ...

测试一个元素是否有一个带有两个或更多句点的描述子元素。

但是,我会将您的 XSLT 更改为:

  <!-- this part replaces your <ul> code above -->
  <ul>
     <xsl:apply-templates
         select="//PgIndexElementItem[not(contains(Description, '.'))]" />
  </ul>      

更新了这个模板:

<!-- add this new template -->
<xsl:template match="PgIndexElementItem">
   <li>
      <a href="ResolvedURL/ServerRelative"><xsl:value-of select="Title"/></a>
      <xsl:variable name="prefix" select="concat(Description, '.')"/>
      <xsl:variable name="childOptions"
         select="../PgIndexElementItem[starts-with(Description, $prefix)
           and not(contains(substring-after(Description, $prefix), '.'))]"/>
      <xsl:if test="$childOptions">
         <ul>
            <xsl:apply-templates select="$childOptions" />
         </ul>
      </xsl:if>
   </li>
</xsl:template>

这将避免不必要的代码重复,以及不需要的空 &lt;ul&gt; 元素。

我对描述子项的解释方式做了一些假设......例如“200.100”应该出现在“200”下的子列表中,而不是“100”下。

【讨论】:

@jrottier - 在您发表评论几秒钟后,我添加了一个关于 XSLT 的重要建议。 哇!那太棒了!工作几乎完美!我在几页上测试了它!唯一的问题是某些元素在不应该重复时重复。我在上面的问题中添加了一个示例。 @jrottier:你能告诉我们哪些元素不应该重复吗?并确保您的示例 XML 包含这些元素,无论它们出现在哪里……以及它们的父菜单项。 @jrottier:另外,我们可以假设在您的输入 XML 中,菜单项的出现顺序与您希望它们出现在输出中的顺序相同吗?例如。 “200”总是出现在“200.*”之前? @LarsH 只有当它是第三级导航元素时才会出现问题。如果您查看我在问题中发布的 XML 示例,那么最后一个 PgIndexElementInfo 就是问题所在。而且我确实有一个带有第四级导航元素的页面,它会导致同样的问题。因此,发生这种情况的两个实例将是以下元素:400.300.200.100 和 400.300.100。这有帮助吗?【参考方案2】:

使用

string-length(Description) - string-length(translate(Description, '.',''))  = 2

这对任何数字 $n 都有效(而“substring-after”技术在一般情况下根本无法使用):

string-length(Description) - string-length(translate(Description, '.',''))  = $n

【讨论】:

+1 聪明...我一直在使用 translate() 寻找类似的东西,但无法做到。 @LarsH:是的,translate() 是最通用的 XPath 函数之一。 还有:string-length(translate(Description,translate(Description,'.',''),'')) @Alejandro: 是的,但是这些太多了translate()s :) 可能我的回答效率更高。 是的。我认为最外面的translate() 会使表达式达到指数复杂度。【参考方案3】:

我看起来您正在处理嵌套的 PgIndexElementItem 元素 - 如果它们嵌套在多个层中,您应该考虑重构您的 XSL 以使用递归模板(假设每个级别的 HTML 输出是可预测的)。

在编写时,您的 for-each 循环选择当前元素的所有 PgIndexElementItem 后代,然后在遇到内部 for-each 循环时再次执行此操作。可能不是你想要的。

【讨论】:

“当前元素的所有 PgIndexElementItem 后代” - 实际上是根节点 (/) 的所有 PgIndexElementItem 后代。当前节点不考虑;那将是“.//PgIndexElementItem”。但我同意重构......

以上是关于XSLT 包含两个句点的主要内容,如果未能解决你的问题,请参考以下文章

如何使用包含点/句点的列名创建火花数据框?

当文件名包含句点时如何引用python包

GAE app.yaml:如何设置包含句点的环境变量?

MalformedJwtException:JWT 字符串必须恰好包含 2 个句点字符

使用 XSLT 过滤不包含节点的 XYZ

XSLT - 创建一个应该包含唯一和排序数据的变量