Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting XSLT是否只显示术语表索引的唯一值?_Sorting_Xslt_Xslt 1.0_Xslt Grouping - Fatal编程技术网

Sorting XSLT是否只显示术语表索引的唯一值?

Sorting XSLT是否只显示术语表索引的唯一值?,sorting,xslt,xslt-1.0,xslt-grouping,Sorting,Xslt,Xslt 1.0,Xslt Grouping,本词汇表从每个条目的第一个字母派生索引。我正试图找出如何只显示唯一的值。查看了前面的兄弟姐妹和position(),但似乎找不到正确的方法。我不得不使用XSLT1.0和属性 glossary.xml <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="glossary.xsl"?> <include> <file name="data.xml"

本词汇表从每个条目的第一个字母派生索引。我正试图找出如何只显示唯一的值。查看了前面的兄弟姐妹和position(),但似乎找不到正确的方法。我不得不使用XSLT1.0和属性

glossary.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="glossary.xsl"?>
<include>
    <file name="data.xml"/>
</include>

data.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<glossary>
    <entry term="cantaloupe" definition="A kind of melon"/>
    <entry term="banana" definition="A tropical yellow fruit"/>
    <entry term="apple" definition="A red fruit with seeds"/>
    <entry term="orange" definition="An orange citrus fruit"/>  
    <entry term="Cherry"  definition="A red fruit that grows in clusters "/>
    <entry term="cranberry" definition="A sour berry enjoyed at Thanksgiving"/>
    <entry term="avocado"  definition="A mellow fruit enjoyed in guacamole"/>
</glossary>

glossary.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
    <xsl:template match="/">
        <html>
            <head></head>
            <body>
            <!-- Index: how to show unique values? -->
                <xsl:for-each select="document('data.xml')/glossary/entry" >
                    <xsl:sort select="@term" data-type="text" order="ascending" case-order="upper-first"/> 
                    <xsl:variable name="initial" select="substring(@term,1,1)" />
                    <a href="#{$initial}"><xsl:value-of select="$initial" /></a> |  
                </xsl:for-each>
            <!-- Glossary -->   
                <dl>
                    <xsl:for-each select="document('data.xml')/glossary/entry" >
                        <xsl:sort select="@term" data-type="text" order="ascending" case-order="upper-first"/> 
                        <xsl:variable name="initial" select="substring(@term,1,1)" />
                        <!-- Alphabetical header: how to only the first instance of each letter? -->
                        <a name="{$initial}"><h1><xsl:value-of select="$initial" /></h1></a> 
                        <dt><xsl:apply-templates select="@term"/></dt>
                        <dd><xsl:apply-templates select="@definition"/></dd>
                    </xsl:for-each>
                </dl> 
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>   

|  
迄今为止的产出

a | a | b | c | c | o|

a
苹果
有种子的红色水果

a
鳄梨
在鳄梨酱中品尝的醇香水果

b
香蕉
热带黄色水果

c
哈密瓜
一种甜瓜

C
樱桃
成簇生长的红色水果

c
蔓越莓
感恩节享用的酸浆果

o
橙色
一种柑橘类水果



期望输出

a|b|c|o

a
苹果
有种子的红色水果

鳄梨
在鳄梨酱中品尝的醇香水果

b
香蕉
热带黄色水果

c
哈密瓜
一种甜瓜

樱桃
成簇生长的红色果实

蔓越莓
感恩节享用的酸浆果

o
橙色

一种柑橘类水果你需要的技术叫做Muenchian分组法。首先定义一个键,该键按照条目元素术语的首字母小写来对条目元素进行分组

<xsl:key name="entryByInitial" match="entry" use="translate(substring(@term, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
并定义一个单独的模板

<xsl:template match="entry">
  <dt><xsl:apply-templates select="@term"/></dt>
  <dd><xsl:apply-templates select="@definition"/></dd>
</xsl:template>

您需要的技术称为Muenchian分组。首先定义一个键,该键按照条目元素术语的首字母小写来对条目元素进行分组

<xsl:key name="entryByInitial" match="entry" use="translate(substring(@term, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
并定义一个单独的模板

<xsl:template match="entry">
  <dt><xsl:apply-templates select="@term"/></dt>
  <dd><xsl:apply-templates select="@definition"/></dd>
</xsl:template>

这是一个分组问题的示例,在XSLT1.0中,进行分组的既定方法是使用Muenchian分组。不幸的是,您的场景需要在上面找到小写字符,这在XSLT1.0中有点混乱

尽管如此,我还是提出了一个解决方案,如下所示:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" doctype-system="about:legacy-compat" 
              encoding="UTF-8" indent="yes" />

  <xsl:key name="kEntryInitial" match="entry/@term"
           use="translate(substring(., 1, 1), 
             'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
             'abcdefghijklmnopqrstuvwxyz')"/>

  <xsl:template match="/">
    <html>
      <head></head>
      <body>
        <!-- Jump into the data.xml DOM so that keys work -->
        <xsl:apply-templates select="document('data.xml')/glossary" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="/glossary">
    <!-- Select terms with distinct initials (case invariant) -->
    <xsl:variable name="termsByDistinctInitial"
                  select="entry/@term[generate-id() = 
                             generate-id(key('kEntryInitial', 
                                            translate(substring(., 1, 1), 
                                            'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                            'abcdefghijklmnopqrstuvwxyz'))[1])]" />

    <!-- Header -->
    <xsl:apply-templates select="$termsByDistinctInitial" mode="header">
      <xsl:sort select="." data-type="text" order="ascending" />
    </xsl:apply-templates>

    <!-- Glossary -->
    <dl>
      <xsl:apply-templates select="$termsByDistinctInitial" mode="main">
        <xsl:sort select="." data-type="text" order="ascending" />
      </xsl:apply-templates>
    </dl>
  </xsl:template>

  <xsl:template match="@term" mode="header">
    <xsl:variable name="initial">
      <xsl:call-template name="ToLower">
        <xsl:with-param name="value" select="substring(., 1, 1)" />
      </xsl:call-template>
    </xsl:variable>

    <a href="#{$initial}">
      <xsl:value-of select="$initial" />
    </a>
    <xsl:if test="position() != last()">
      <xsl:text> |</xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="@term" mode="main">
    <xsl:variable name="initial">
      <xsl:call-template name="ToLower">
        <xsl:with-param name="value" select="substring(., 1, 1)" />
      </xsl:call-template>
    </xsl:variable>
    <a name="{$initial}">
      <h1>
        <xsl:value-of select="$initial" />
      </h1>
    </a>

    <xsl:apply-templates select="key('kEntryInitial', $initial)/.." />
  </xsl:template>

  <xsl:template match="entry">
    <dt>
      <xsl:apply-templates select="@term"/>
    </dt>
    <dd>
      <xsl:apply-templates select="@definition"/>
    </dd>
  </xsl:template>

  <xsl:template name="ToLower">
    <xsl:param name="value" />
    <xsl:value-of select="translate(substring($value, 1, 1), 
                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                      'abcdefghijklmnopqrstuvwxyz')"/>
  </xsl:template>
</xsl:stylesheet>

当然,最终输出与第一个示例相同。如果XSLT处理器支持
node-set()
函数,也可以在单个XSLT中执行这两个处理步骤。

这是一个分组问题的示例,在XSLT 1.0中,进行分组的既定方法是使用Muenchian分组。不幸的是,您的场景需要在上面找到小写字符,这在XSLT1.0中有点混乱

尽管如此,我还是提出了一个解决方案,如下所示:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" doctype-system="about:legacy-compat" 
              encoding="UTF-8" indent="yes" />

  <xsl:key name="kEntryInitial" match="entry/@term"
           use="translate(substring(., 1, 1), 
             'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
             'abcdefghijklmnopqrstuvwxyz')"/>

  <xsl:template match="/">
    <html>
      <head></head>
      <body>
        <!-- Jump into the data.xml DOM so that keys work -->
        <xsl:apply-templates select="document('data.xml')/glossary" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="/glossary">
    <!-- Select terms with distinct initials (case invariant) -->
    <xsl:variable name="termsByDistinctInitial"
                  select="entry/@term[generate-id() = 
                             generate-id(key('kEntryInitial', 
                                            translate(substring(., 1, 1), 
                                            'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                                            'abcdefghijklmnopqrstuvwxyz'))[1])]" />

    <!-- Header -->
    <xsl:apply-templates select="$termsByDistinctInitial" mode="header">
      <xsl:sort select="." data-type="text" order="ascending" />
    </xsl:apply-templates>

    <!-- Glossary -->
    <dl>
      <xsl:apply-templates select="$termsByDistinctInitial" mode="main">
        <xsl:sort select="." data-type="text" order="ascending" />
      </xsl:apply-templates>
    </dl>
  </xsl:template>

  <xsl:template match="@term" mode="header">
    <xsl:variable name="initial">
      <xsl:call-template name="ToLower">
        <xsl:with-param name="value" select="substring(., 1, 1)" />
      </xsl:call-template>
    </xsl:variable>

    <a href="#{$initial}">
      <xsl:value-of select="$initial" />
    </a>
    <xsl:if test="position() != last()">
      <xsl:text> |</xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="@term" mode="main">
    <xsl:variable name="initial">
      <xsl:call-template name="ToLower">
        <xsl:with-param name="value" select="substring(., 1, 1)" />
      </xsl:call-template>
    </xsl:variable>
    <a name="{$initial}">
      <h1>
        <xsl:value-of select="$initial" />
      </h1>
    </a>

    <xsl:apply-templates select="key('kEntryInitial', $initial)/.." />
  </xsl:template>

  <xsl:template match="entry">
    <dt>
      <xsl:apply-templates select="@term"/>
    </dt>
    <dd>
      <xsl:apply-templates select="@definition"/>
    </dd>
  </xsl:template>

  <xsl:template name="ToLower">
    <xsl:param name="value" />
    <xsl:value-of select="translate(substring($value, 1, 1), 
                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                      'abcdefghijklmnopqrstuvwxyz')"/>
  </xsl:template>
</xsl:stylesheet>

当然,最终输出与第一个示例相同。如果您的XSLT处理器支持
node-set()
函数,也可以在一个XSLT中执行这两个处理步骤。

感谢您向我演示如何使用Muenchian分组。我可以使用@JLRishe解决方案,但仍然在摆弄伊恩·罗伯茨的版本。但不确定如何评估哪个更有效。我想XSLT1.0不适合这种情况。另外,我想知道下套管是否必要?xsl:sort是否将大小写视为不同的字符?
xsl:sort
将大小写视为不同的字符,但这并不是真正的问题。下框很重要,因为(1)如果它们的大小写不一致,Muenchian分组技术会将它们视为单独的字符;(2)您希望标题中的大小写一致。可以通过将值与前面的值进行比较来进行分组,但是它实际上并不干净,而且这种方法不被鼓励,因为它在计算上非常低效,特别是在源数据中有很多行的情况下。本月早些时候,迪米特里·诺瓦切夫(Dimitre Novatchev)评论了一种情况,他看到一个
之前的兄弟姐妹
分组操作需要超过40分钟,而Muenchian方法只需2秒钟。在计算机科学术语中,“Muenchian具有O(N)时间复杂性,而同级比较分组的时间复杂性是二次的——O(N^2)。”XSLT不是过程语言,它只是描述如何将一个XML文档转换为另一个XML文档。尽管名称
不一定要由XSLT处理器作为顺序循环来实现,但处理器可以自由地以任何顺序计算各种“迭代”的值,甚至可以在多个线程中并行计算,只要最终输出的顺序正确(例如,它可以按文档顺序处理元素,然后在输出片段时在末尾应用
排序)。您可以使用XPath表达式将
中的当前元素与文档顺序中的前一个同级元素进行比较,但无法访问“上一个”
所施加的排序中的元素。感谢您向我展示了如何使用Muenchian分组。我可以让@JLRishe解决方案工作,但仍然在摆弄ian roberts的版本。但不确定如何评估哪一个更有效。我猜xslt 1.0不适合这种情况。另外-我想知道是否需要向下编译sary?xsl:sort是否将大写和小写视为不同的字符?
xsl:sort
将大写和小写视为不同的字符,但这并不是一个真正的问题。小写很重要,因为(1)如果大写和小写不一致,Muenchian分组技术会将它们视为单独的字符;(2)您将需要一致的ca
<glossary>
  <entry initial="c" term="cantaloupe" definition="A kind of melon" />
  <entry initial="b" term="banana" definition="A tropical yellow fruit" />
  <entry initial="a" term="apple" definition="A red fruit with seeds" />
  <entry initial="o" term="orange" definition="An orange citrus fruit" />
  <entry initial="c" term="Cherry" definition="A red fruit that grows in clusters " />
  <entry initial="c" term="cranberry" definition="A sour berry enjoyed at Thanksgiving" />
  <entry initial="a" term="avocado" definition="A mellow fruit enjoyed in guacamole" />
</glossary>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" doctype-system="about:legacy-compat" 
              encoding="UTF-8" indent="yes" />

  <xsl:key name="kEntryInitial" match="entry/@initial" use="."/>

  <xsl:template match="/">
    <html>
      <head></head>
      <body>
        <!-- Jump into the data.xml DOM so that keys work -->
        <xsl:apply-templates select="document('data2.xml')/glossary" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="/glossary">
    <!-- Select terms with distinct initials (case invariant) -->
    <xsl:variable name="termsByDistinctInitial"
                  select="entry/@initial[generate-id() = 
                             generate-id(key('kEntryInitial', .)[1])]" />

    <!-- Header -->
    <xsl:apply-templates select="$termsByDistinctInitial" mode="header">
      <xsl:sort select="." data-type="text" order="ascending" />
    </xsl:apply-templates>

    <!-- Glossary -->
    <dl>
      <xsl:apply-templates select="$termsByDistinctInitial" mode="main">
        <xsl:sort select="." data-type="text" order="ascending" />
      </xsl:apply-templates>
    </dl>
  </xsl:template>

  <xsl:template match="@initial" mode="header">
    <a href="#{.}">
      <xsl:value-of select="." />
    </a>
    <xsl:if test="position() != last()">
      <xsl:text> |</xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="@initial" mode="main">
    <a name="{.}">
      <h1>
        <xsl:value-of select="." />
      </h1>
    </a>

    <xsl:apply-templates select="key('kEntryInitial', .)/.." />
  </xsl:template>

  <xsl:template match="entry">
    <dt>
      <xsl:apply-templates select="@term"/>
    </dt>
    <dd>
      <xsl:apply-templates select="@definition"/>
    </dd>
  </xsl:template>
</xsl:stylesheet>