Если число повторяется, показать его только один раз - PullRequest
2 голосов
/ 29 июля 2011

Привет, если у меня есть следующий входной XML-файл

<data>
<group id= "1">
<phrase>Doc1</phrase>
<document refid ="3"/>
<document refid ="5"/>
<document refid= "1"/>
</group>
<group id= "2">
 <phrase>Doc2</phrase>
<document refid ="2"/>
<document refid ="3"/>
<document refid= "6"/>
</group>
  <group id= "3">
 <phrase>Doc3</phrase>
<document refid ="2"/>
<document refid ="3"/>
<document refid= "4"/>
</group>
</data>

Возможно ли иметь вывод, который проверяет каждую группу, чтобы увидеть, не был ли отображен номер документа "refid" в предыдущих группах?Например, я хотел бы, чтобы мой вывод был

<data>
 <group id= "1">
 <phrase>Doc1</phrase>
<document refid ="3"/>
<document refid ="5"/>
<document refid= "1"/>
</group>
<group id= "2">
 <phrase>Doc2</phrase>
<document refid ="2"/>
<document refid= "6"/>
</group>
  <group id= "3">
 <phrase>Doc3</phrase>
<document refid= "4"/>
</group>
</data>

Я пытаюсь сделать это в XSLT 1.0.Я надеюсь, что это ясно объясняет вопрос.Буду очень признателен за вашу помощь.Спасибо

Ответы [ 2 ]

1 голос
/ 31 июля 2011

Вот эффективное и короткое решение с использованием ключей (мюнхенская группировка ) :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="kDocById" match="document" use="@refid"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="group">
        <xsl:copy>
            <xsl:apply-templates select=
            "@*
            |
             node()[not(self::document)]
            |
             document
                  [generate-id()
                  =
                  generate-id(key('kDocById', @refid)[1])
                  ]"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

, когда это преобразование применяется к предоставленномуXML-документ (отражающий последнее уточнение, внесенное в комментарии ОП):

<data>
    <group id= "1">
        <phrase>Doc1</phrase>
        <document refid ="3"/>
        <document refid ="5"/>
        <document refid= "1"/>
    </group>
    <group id= "2">
        <phrase>Doc2</phrase>
        <document refid ="2"/>
        <document refid ="3"/>
        <document refid= "6"/>
    </group>
    <group id= "3">
        <phrase>Doc3</phrase>
        <document refid ="2"/>
        <document refid ="3"/>
        <document refid= "4"/>
    </group>
</data>

желаемый, правильный результат получается :

<data>
   <group id="1">
      <phrase>Doc1</phrase>
      <document refid="3"/>
      <document refid="5"/>
      <document refid="1"/>
   </group>
   <group id="2">
      <phrase>Doc2</phrase>
      <document refid="2"/>
      <document refid="6"/>
   </group>
   <group id="3">
      <phrase>Doc3</phrase>
      <document refid="4"/>
   </group>
</data>
1 голос
/ 29 июля 2011

Это, кажется, делает трюк:

$ cat style.xsl

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

    <!--
    This templates matches the document elements with a @refid that has already been used
    in on of the previous groups. They are simply ignored.
    -->
    <xsl:template match="document[../preceding-sibling::group/document/@refid = current()/@refid]" />


    <!--
    Everything else gets copied to the output.
    -->
    <xsl:template match="@*|*|text()">
        <xsl:copy>
            <xsl:apply-templates select="@*|*|text()" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

$ xsltproc style.xsl input.xml

<?xml version="1.0"?>
<data>
    <group id="1">
        <document refid="3"/>
        <document refid="5"/>
        <document refid="1"/>
    </group>
    <group id="2">
        <document refid="2"/>

        <document refid="6"/>
    </group>
    <group id="3">


        <document refid="4"/>
    </group>
</data>

Редактировать: чтобы включить его в таблицу стилей, попробуйте изменить for-each в строке 49 на:

<xsl:for-each select="document[not(../preceding-sibling::group/document/@refid = current()/@refid)]">
...