使用 XSLT 1.0 对相邻项进行分组 [英] Grouping Adjacent Items using XSLT 1.0

查看:28
本文介绍了使用 XSLT 1.0 对相邻项进行分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望得到一些关于如何使用 XSLT 1.0 将无序列表中同名相邻元素分组的建议.

I'm hoping to get some advice on how to group adjacent elements with the same name in an unordered list using XSLT 1.0.

以下是一些 XML 示例:

Here's some example XML:

<Article>
  <TextContent>
    <p>lorem</p>
    <VisualContent id="1" />
    <VisualContent id="2" />
    <VisualContent id="3" />
    <p>ipsum</p>
    <VisualContent id="4" />
    <p>dolor</p>
    <VisualContent id="5" />
  </TextContent>
</Article>

这是我想要的输出:

<Article>
  <HtmlContent>
    <p>lorem</p>
    <ul>
      <li><img data-id="1" /></li>
      <li><img data-id="2" /></li>
      <li><img data-id="3" /></li>
    </ul>
    <p>ipsum</p>
    <img data-id="4" />
    <p>dolor</p>
    <img data-id="5" />
  </HtmlContent>
</Article>

不幸的是,XSLT 1.0 对此有严格的要求.任何建议将不胜感激.

Unfortunately, XSLT 1.0 is a strict requirement for this one. Any suggestions would be greatly appreciated.

推荐答案

转成 的部分我跳过了><VisualContent id="n"/> 变成了 <img data-id="n"/> 因为没有这些干扰,这个问题已经够难了.

I have skipped the part where <TextContent> turns into <HtmlContent> and <VisualContent id="n" /> becomes <img data-id="n" /> because the question is difficult enough without these distractions.

我选择的方法查看名称与当前元素名称相同的第一个前面的兄弟.该兄弟的唯一ID是可以将同名相邻元素分组的键:

The method I have chosen looks at the first preceding sibling whose name is not the same as the current element's name. The unique ID of that sibling is the key by which the adjacent elements of same name can be grouped:

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

<xsl:key name="prevByName" match="TextContent/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" />

<xsl:template match="/">
<Article><TextContent>
    <xsl:for-each select="Article/TextContent/*[generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])]">
        <xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" />
        <xsl:choose>
            <xsl:when test="count($myGroup) > 1">
                <ul>
                    <xsl:for-each select="$myGroup">
                    <li><xsl:copy-of select="."/></li>
                    </xsl:for-each>
                </ul>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</TextContent></Article>
</xsl:template>
</xsl:stylesheet>

应用于您的输入示例时,会产生以下结果:

When applied to your input example, the following result is produced:

<?xml version="1.0" encoding="utf-8"?>
<Article>
   <TextContent>
      <p>lorem</p>
      <ul>
         <li>
            <VisualContent id="1"/>
         </li>
         <li>
            <VisualContent id="2"/>
         </li>
         <li>
            <VisualContent id="3"/>
         </li>
      </ul>
      <p>ipsum</p>
      <VisualContent id="4"/>
      <p>dolor</p>
      <VisualContent id="5"/>
   </TextContent>
</Article>

<小时>

这是一个仅对相邻的VisualContent"元素进行分组的修改版本:


Here's a modified version that only groups adjacent "VisualContent" elements:

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

<xsl:key name="prevByName" match="TextContent/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" />

<xsl:template match="/Article/TextContent">
    <Article><TextContent>
        <xsl:apply-templates select="*"/>
    </TextContent></Article>
</xsl:template>

<xsl:template match="TextContent/*[not(self::VisualContent)]">
    <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="VisualContent[generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])]">
<xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" />
    <xsl:choose>
        <xsl:when test="count($myGroup) > 1">
            <ul>
                <xsl:for-each select="$myGroup">
                <li><xsl:copy-of select="."/></li>
                </xsl:for-each>
            </ul>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

这可能需要一些精简,但我认为原理很清楚,我需要睡一觉......

This could probably use some streamlining, but I think the principle is clear and I need to get some sleep...

这篇关于使用 XSLT 1.0 对相邻项进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆