2016-04-12 4 views
1

Начальная точка является XML-список, какСортировка списка и устранение дубликатов в XSLT?

<attributes> 
     <para role="tocmain1"/> 
     <para role="tocmain1"/> 
     <other style="fix"/> 
     <other style="fix"/> 
     <para role="tocmain2"/> 
     <para role="tocmain2"/> 
     <para role="tocmain2"/> 
     <para role="tocmain3"/> 
     <para role="tocmain3"/> 
     <para language="de"/> 
     <para language="de"/> 
     <para role="tocmain3"/> 
</attributes> 

Я хотел бы, чтобы уменьшить число вхождений каждого элемента + атрибут + экземпляр значения только в одном случае.

Как это:

<attributes> 
    <other style="fix"/> 
    <para language="de"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/>  
</attributes>` 

До сих пор я только удалось упорядочить список по алфавиту. До сих пор все мои попытки сократить список были тщетными.

Это то, что я прямо сейчас:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
<xsl:template match="/"> 
    <attributes> 
     <xsl:for-each select="attributes/node()">    
      <xsl:sort select="name()" order="ascending"/>   
      <xsl:sort select="@*" order="ascending"/>     
      <xsl:choose> 
       <xsl:when test="name() = name(preceding::*[1]) and self::node()/@* = preceding::*/@*"/> 
       <xsl:otherwise> 
        <xsl:copy-of select="."/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each> 
    </attributes> 
</xsl:template> 
</xsl:stylesheet> 

ответ

0

Хорошо, по предложению Даниэля Хейли я нашел ответ, который работает на мой вопрос.

Я теперь с помощью двух Xsl один за другим:

  1. XSL, который дает неупорядоченный список без дубликатов

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
        <xsl:output indent="yes"/> 
        <xsl:strip-space elements="*"/>  
        <xsl:template match="@*|node()"> 
         <xsl:copy> 
          <xsl:apply-templates select="@*|node()"/> 
         </xsl:copy> 
        </xsl:template>  
        <xsl:template match="/*"> 
         <xsl:copy> 
          <xsl:apply-templates select="@*"/> 
          <xsl:for-each-group select="*" group-by="@*"> 
           <xsl:sort select="@*"/> 
           <xsl:apply-templates select="current-group()[1]"/> 
          </xsl:for-each-group> 
         </xsl:copy> 
        </xsl:template>  
    </xsl:stylesheet>
  2. XSL, который упорядочивает список:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 
        <xsl:output indent="yes"/> 
        <xsl:strip-space elements="*"/> 
        <xsl:template match="/"> 
         <attributes> 
          <xsl:for-each select="attributes/node()">     
           <xsl:sort select="name()" order="ascending"/> 
           <xsl:sort select="name(@*)" order="ascending"/>     
           <xsl:sort select="@*" order="ascending"/>     
           <xsl:copy-of select="."/>     
          </xsl:for-each> 
         </attributes> 
        </xsl:template>   
    </xsl:stylesheet>
  3. Результат по запросу:

    <attributes> 
        <other style="fix"/> 
        <para language="de"/> 
        <para role="tocmain1"/> 
        <para role="tocmain2"/> 
        <para role="tocmain3"/>  
    </attributes>

Спасибо за помощь мне найти ответ и извините за вводящие в заблуждение пример XML! Если кто-то знает, как объединить два шага в один скрипт: добро пожаловать!

0

Ваш XSLT генерирует ваш запрошенный XML по модулю некоторые вопросы форматирования, которые могут быть решены с xsl:output и xsl:strip-space. Кроме того, вы можете использовать distinct-values(), чтобы оптимизировать код:

Ваш входной XML документ,

<attributes> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain3"/> 
    <para role="tocmain3"/> 
</attributes> 

данное этому обтекаемой XSLT,

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

    <xsl:template match="/attributes"> 
    <attributes> 
     <xsl:for-each select="distinct-values(para/@role)"> 
     <xsl:sort select="." order="ascending"/> 
     <para role="{.}"/> 
     </xsl:for-each> 
    </attributes> 
    </xsl:template> 
</xsl:stylesheet> 

будет производить этот вывод XML документ,

<?xml version="1.0" encoding="UTF-8"?> 
<attributes> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
</attributes> 

в соответствии с просьбой.

1

Вы также можете использовать xsl:for-each-group и xsl:apply-templates для первого узла в группе. Это должно облегчить добавление любых дополнительных преобразований, которые могут возникнуть в будущем.

XML Input (изменен, чтобы показать правильную сортировку)

<attributes> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain1"/> 
    <para role="tocmain3"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
</attributes> 

XSLT 2,0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

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

    <xsl:template match="/*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:for-each-group select="*" group-by="@role"> 
     <xsl:sort select="@role"/> 
     <xsl:apply-templates select="current-group()[1]"/> 
     </xsl:for-each-group> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

XML Output

<attributes> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
</attributes> 
+0

Я должен был явно указать, что список отличается по элементам, атрибутам и значениям. Я отредактировал свой список на этом посту. Все ваши попытки, которые используют @role, не будут работать. Вот почему я попытался использовать */@ *. Мне нужно удалить дубликаты на основе того же элемента + тот же атрибут + одно и то же значение. – rena

Смежные вопросы