2017-02-09 7 views
0

Просьба предложить, как избежать дублирования списка элементов с помощью xsl: key (я получил результат из метода переменной, но это не эффективный способ). Пожалуйста, предложите.Как получить уникальную структуру элементов с помощью xsl: key

В моем документе «Ref» - ​​это основной элемент, в котором он имеет несколько потомков. Нужно перечислить только элементы 'Ref', где их структура (только имя элементов, а не контент) уникальны. Если < Ссылка > </а > < б/б > </Ref > и < Ссылка > </а > < б/б > </Ссылка >, то только сначала <Ref> должен быть отображен. В данном входе игнорируются элементы «au» и «ed» в качестве их предка.

Входной XML:

<article> 
<Ref id="ref1"> 
    <RefText> 
     <authors><au><snm>Kishan</snm><fnm>TR</fnm></au><au><snm>Rudramuni</snm><fnm>TP</fnm></au></authors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2016</Year><vol>1</vol> 
     <fpage>12</fpage><lpage>14</lpage> 
    </RefText></Ref><!-- should list --> 

<Ref id="ref2"> 
    <RefText> 
     <authors><au><snm>Rudramuni</snm><fnm>TP</fnm></au></authors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><vol>2</vol> 
     <fpage>22</fpage><lpage>24</lpage> 
     </RefText></Ref><!-- This Ref should not list in output xml, because 'authors, articleTitle, like other same type elements present, ref2 is same as ref1. --> 

<Ref id="ref3"> 
    <RefText> 
     <authors><au><snm>Likhith</snm><fnm>MD</fnm></au></authors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><fpage>22</fpage><lpage>24</lpage> 
     </RefText></Ref><!-- It should list, bcs, 'vol' missing here, then it is unique in structure with respect to prev Refs --> 

<Ref id="ref4"> 
    <RefText> 
     <authors><au><snm>Kowshik</snm><fnm>MD</fnm></au></authors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><fpage>22</fpage> 
     </RefText></Ref><!-- should list, bcs, 'lpage' missing --> 

<Ref id="ref5"> 
    <RefText> 
     <editors><au><snm>Dhyan</snm><fnm>MD</fnm></au></editors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><fpage>22</fpage> 
     </RefText></Ref><!-- should list, bcs, 'editors' missing --> 

<Ref id="ref6"> 
    <RefText> 
     <editors><ed><snm>Kishan</snm><fnm>TR</fnm></ed></editors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year> 
     </RefText></Ref><!-- should list --> 

<Ref id="ref7"> 
    <RefText> 
     <editors><ed><snm>Vivan</snm><fnm>S</fnm></ed></editors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year> 
     </RefText></Ref><!-- should not, same type elements in ref6 and ref7 --> 

<Ref id="ref8"> 
    <RefText><editors><au><snm>Dhyan</snm><fnm>MD</fnm></au><au><snm>Dhyan</snm><fnm>MD</fnm></au></editors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><fpage>22</fpage> 
     </RefText></Ref><!-- should not, bcs, 'Ref5 and Ref8' are having same elements --> 

</article> 

XSLT 2.0: Здесь я рассмотрел переменные для хранения предыдущих рефов потомков имена.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 

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

<xsl:template match="article"> 
    <article> 

     <xsl:for-each select="descendant::Ref"> 
      <xsl:variable name="varPrev"> 
      <xsl:for-each select="preceding::Ref"> 
       <a> 
        <xsl:text>|</xsl:text> 
         <xsl:for-each select="descendant::*[not(ancestor-or-self::au) and not(ancestor-or-self::ed)]"> 
          <xsl:value-of select="name()"/> 
         </xsl:for-each> 
        <xsl:text>|</xsl:text> 
       </a> 
      </xsl:for-each> 
     </xsl:variable> 
      <xsl:variable name="varPresent"> 
       <a> 
        <xsl:text>|</xsl:text> 
         <xsl:for-each select="descendant::*[not(ancestor-or-self::au) and not(ancestor-or-self::ed)]"> 
          <xsl:value-of select="name()"/> 
         </xsl:for-each> 
        <xsl:text>|</xsl:text> 
       </a> 
      </xsl:variable> 
      <xsl:if test="not(contains($varPrev, $varPresent))"> 
       <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> 
      </xsl:if> 

     </xsl:for-each> 
    </article> 
</xsl:template> 

<!--xsl:key name="keyRef" match="Ref" use="descendant::*"/> 

<xsl:template match="article"> 
    <xsl:for-each select="descendant::Ref"> 
     <xsl:if test="count('keyRef', ./name())=1"> 
      <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:template--> 

</xsl:stylesheet> 

Обязательный Результат:

<article> 
<Ref id="ref1"> 
    <RefText> 
     <authors><au><snm>Kishan</snm><fnm>TR</fnm></au><au><snm>Rudramuni</snm><fnm>TP</fnm></au></authors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2016</Year><vol>1</vol> 
     <fpage>12</fpage><lpage>14</lpage> 
    </RefText></Ref> 
<Ref id="ref3"> 
    <RefText> 
     <authors><au><snm>Likhith</snm><fnm>MD</fnm></au></authors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><fpage>22</fpage><lpage>24</lpage> 
     </RefText></Ref> 
<Ref id="ref4"> 
    <RefText> 
     <authors><au><snm>Kowshik</snm><fnm>MD</fnm></au></authors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><fpage>22</fpage> 
     </RefText></Ref> 
<Ref id="ref5"> 
    <RefText><editors><au><snm>Dhyan</snm><fnm>MD</fnm></au></editors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year><fpage>22</fpage> 
     </RefText></Ref> 
<Ref id="ref6"> 
    <RefText> 
     <editors><ed><snm>Kishan</snm><fnm>TR</fnm></ed></editors> 
     <artTitle>The article1</artTitle><jTitle>Journal title</jTitle> 
     <Year>2017</Year> 
     </RefText></Ref> 
</article> 
+0

Что именно вы имеете в виду под «* игнорирование ' au 'и' ed 'в качестве своего предка. * "? Вы хотите рассмотреть всю структуру или нет? Если нет, то какова точная логика, чтобы исключить некоторые ее части? - Кроме того, будет ли порядок * элементов одинаковым во всех 'Ref'? –

+0

** 1.** Рассмотрим только имя автора, если только две, три, более также являются единственной основной группой авторов. Поскольку ref могут иметь разные номера авторов, но 'vol' 'page' другие элементы могут быть одинаковыми. ** 2. ** Различный по порядку также является уникальным, т. Е. «A, b» является уникальным от «b, a». (порядок отличается, тогда его нужно рассматривать как уникальное). –

+0

Я не понял # 1. Я подозреваю, что если вы удалите текстовые значения (+ те элементы, которые вы не хотите учитывать) и выполните «глубокое()« сравнение результирующих узлов », вы можете получить ожидаемый результат. –

ответ

1

Вот попытка использовать ключ, вычисленный аналогично вашего сравнения строк:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:mf="http://example.com/mf" exclude-result-prefixes="mf xs"> 

    <xsl:function name="mf:fingerprint" as="xs:string"> 
     <xsl:param name="input-element" as="element()"/> 
     <xsl:value-of select="for $d in $input-element/descendant::*[not(ancestor-or-self::au) and not(ancestor-or-self::ed)] return node-name($d)" separator="|"/> 
    </xsl:function> 

    <xsl:key name="group" match="Ref" use="mf:fingerprint(.)"/> 

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

    <xsl:template match="Ref[not(. is key('group', mf:fingerprint(.))[1])]"/> 
</xsl:transform> 

кажется, чтобы сделать работу в http://xsltransform.net/bwdwsC, как насколько я могу судить, но я не совсем уверен, что конкатенация имен строк достаточно для работы со всеми типами входов.

+0

Отличное предложение сэр, плюс один. –

1

Я хотел бы предложить следующий подход:

  • удалить потомки authors и editors, наряду со всеми текстовыми узлами;

  • сравнить остальные узлы, используя deep-equal().

Вот упрощенная проверка концепции:

XSLT 2,0

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

<xsl:template match="/article"> 
    <xsl:variable name="first-pass"> 
     <xsl:apply-templates mode="first-pass"/> 
    </xsl:variable> 
    <xsl:copy> 
     <xsl:for-each select="$first-pass/Ref[not(some $ref in preceding-sibling::Ref satisfies deep-equal(RefText, $ref/RefText))]"> 
      <Ref id="{@id}"/> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

<!-- identity transform --> 
<xsl:template match="@*|node()" mode="#all"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" mode="#current"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="authors | editors" mode="first-pass"> 
    <xsl:copy/> 
</xsl:template> 

<xsl:template match="text()" mode="first-pass" priority="0"/> 

</xsl:stylesheet> 

Результат

<?xml version="1.0" encoding="UTF-8"?> 
<article> 
    <Ref id="ref1"/> 
    <Ref id="ref3"/> 
    <Ref id="ref4"/> 
    <Ref id="ref5"/> 
    <Ref id="ref6"/> 
</article> 
+0

Спасибо за предложение глубокого равенства, сэр. –