Muenchian Grouping - группа внутри узла, а не внутри всего документа
Я пытаюсь использовать группировку Muenchian в моем XSLT для группировки подходящих узлов, но я хочу группировать только внутри родительского узла, а не по всему исходному XML-документу.
Учитывая XSLT и XML следующим образом (извинения за длину моего примера кода):
XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>
<xsl:key name="contacts-by-surname" match="contact" use="surname" />
<xsl:template match="records">
<xsl:for-each select="contact[count(. | key('contacts-by-surname', surname)[1]) = 1]">
<xsl:sort select="surname" />
<xsl:value-of select="surname" />,<br />
<xsl:for-each select="key('contacts-by-surname', surname)">
<xsl:sort select="forename" />
<xsl:value-of select="forename" /> (<xsl:value-of select="title" />)<br />
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
XML
<root>
<records>
<contact id="0001">
<title>Mr</title>
<forename>John</forename>
<surname>Smith</surname>
</contact>
<contact id="0002">
<title>Dr</title>
<forename>Amy</forename>
<surname>Jones</surname>
</contact>
<contact id="0003">
<title>Mrs</title>
<forename>Mary</forename>
<surname>Smith</surname>
</contact>
<contact id="0004">
<title>Ms</title>
<forename>Anne</forename>
<surname>Jones</surname>
</contact>
<contact id="0005">
<title>Mr</title>
<forename>Peter</forename>
<surname>Smith</surname>
</contact>
<contact id="0006">
<title>Dr</title>
<forename>Indy</forename>
<surname>Jones</surname>
</contact>
</records>
<records>
<contact id="0001">
<title>Mr</title>
<forename>James</forename>
<surname>Smith</surname>
</contact>
<contact id="0002">
<title>Dr</title>
<forename>Mandy</forename>
<surname>Jones</surname>
</contact>
<contact id="0003">
<title>Mrs</title>
<forename>Elizabeth</forename>
<surname>Smith</surname>
</contact>
<contact id="0004">
<title>Ms</title>
<forename>Sally</forename>
<surname>Jones</surname>
</contact>
<contact id="0005">
<title>Mr</title>
<forename>George</forename>
<surname>Smith</surname>
</contact>
<contact id="0006">
<title>Dr</title>
<forename>Harry</forename>
<surname>Jones</surname>
</contact>
</records>
</root>
РЕЗУЛЬТАТ
Jones,
Amy (Dr)
Anne (Ms)
Harry (Dr)
Indy (Dr)
Mandy (Dr)
Sally (Ms)
Smith,
Elizabeth (Mrs)
George (Mr)
James (Mr)
John (Mr)
Mary (Mrs)
Peter (Mr)
Как мне группировать внутри каждого <records>
и достичь этого результата:
Jones,
Amy (Dr)
Anne (Ms)
Indy (Dr)
Smith,
John (Mr)
Mary (Mrs)
Peter (Mr)
Jones,
Harry (Dr)
Mandy (Dr)
Sally (Ms)
Smith,
Elizabeth (Mrs)
George (Mr)
James (Mr)
2 ответа
Это заняло у меня некоторое время... Я собирался сдаться, но все же продолжил:)
Недостаток функции key заключается в том, что сгенерированный ключ всегда будет для всего xml. Следовательно, вы должны объединить дополнительную информацию в своем ключе, чтобы сделать его более конкретным. Например, ниже, я объединяю положение узла записей, так что я получаю ключи для разных фамилий для каждой записи.
Вот xslt:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>
<xsl:key name="distinct-surname" match="contact" use="concat(generate-id(..), '|', surname)"/>
<xsl:template match="records">
<xsl:for-each select="contact[generate-id() = generate-id(key('distinct-surname', concat(generate-id(..), '|', surname))[1])]">
<xsl:sort select="surname" />
<xsl:value-of select="surname" />,<br />
<xsl:for-each select="key('distinct-surname', concat(generate-id(..), '|', surname))">
<xsl:sort select="forename" />
<xsl:value-of select="forename" /> (<xsl:value-of select="title" />)<br />
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Это результат:
Jones,
Amy (Dr)
Anne (Ms)
Indy (Dr)
Smith,
John (Mr)
Mary (Mrs)
Peter (Mr)
Jones,
Harry (Dr)
Mandy (Dr)
Sally (Ms)
Smith,
Elizabeth (Mrs)
George (Mr)
James (Mr)
Обратите внимание, что результат сортируется по именам тоже. Если вы не хотите сортировать по именам, вам нужно удалить строку <xsl:sort select="forename" />
Существует более простой метод, добавив предикат, который гарантирует, что контакты, участвующие в тесте muench, являются дочерними по отношению к текущим записям.
<xsl:key name="contacts-by-surname" match="contact" use="surname" />
<xsl:template match="records">
<xsl:for-each select="contact[count(. | key('contacts-by-surname', surname)[generate-id(parent::records) = generate-id(current())][1]) = 1]">
<xsl:sort select="surname" />
<xsl:value-of select="surname" />,<br />
<xsl:for-each select="key('contacts-by-surname', surname)[generate-id(parent::records) = generate-id(current()/parent::records)]">
<xsl:sort select="forename" />
<xsl:value-of select="forename" /> (<xsl:value-of select="title" />)<br />
</xsl:for-each>
</xsl:for-each>
</xsl:template>