2015-03-25 15 views
7

Se $ A e $ B sono sequenze, qual è il modo idiomaticamente preferito di testare $ A e $ B per impostare l'uguaglianza? So che il comportamento semantico esistenziale di ($A = $B) rende questa espressione non la risposta. La semantica degli ordini di deep-equal() mi impedisce di usare anche quella.Modo Idomatico per esprimere l'uguaglianza di set in XPath 2.0

mio impulso è quello di utilizzare:

((every $a in $A satisfies $a = $B) and (every $b in $B satisfies $b = $A)) 

ho trovato sorprendentemente poco di impostare test di uguaglianza tramite Google (per essere precisi, ho trovato assolutamente nulla), e non l'ho visto menzionato nel capitolo 8, 9, 10 o 13 di @Michael-Kay. È difficile credere che io sia il primo utente XPath ad aver riscontrato questa necessità. Mi chiedo se sto facendo la domanda sbagliata.

risposta

2

In primo luogo, dipende da come si valuta l'uguaglianza tra gli elementi, ad esempio fai a confrontare due elementi utilizzando "=", "è" , "eq" o "deep-equal"? La tua risposta suggerisce che stai pensando a "=", che è quasi uguale a "eq" se applicato agli elementi, tranne che ha regole di conversione leggermente diverse. E come accade, non è un buon operatore da usare con gli insiemi, perché non è transitivo: untypedAtomic ("4") = 4, untypedAtomic ("4") = "4", ma non (4 = "4"). Quindi supponiamo "eq", che è transitivo tranne che in casi d'angolo che coinvolgono arrotondamenti numerici di valori che sono "quasi uguali".

avevo quindi propenso a suggerire (come altri hanno fatto)

deep-equal(sort($A), sort($B)) 

tranne che alcuni tipi di dati (ad esempio QNames) hanno un operatore di uguaglianza definito, ma nessun ordinamento definito. Quindi funzionerà per interi e stringhe, ma non per QNames.

Ovviamente c'è il metodo O (n^2) indicato nella tua soluzione "impulsiva", ma si può fare di meglio?

Come su

let $A := count(distinct-values($a)) 
let $B := count(distinct-values($b)) 
let $AB := count(distinct-values(($a, $b)) 
return $A = $AB and $B = $AB 

Questo dovrebbe essere O (n log n).

3

Una domanda interessante e ben fatta! Secondo me, usare every e satisfies per superare le proprietà esistenziali dei confronti di sequenza è un metodo abbastanza valido e abbastanza canonico.

Ma dal momento che stai chiedendo un altro approccio: come ordinare le sequenze prima di confrontarle con deep-equal()? Ipotizziamo due sequenze nel seguente foglio di stile:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <xsl:output method="text"/> 

    <xsl:variable name="A" select="('a','b','c')"/> 
    <xsl:variable name="B" select="('a','c','b')"/> 

    <xsl:template match="/"> 
     <xsl:choose> 
      <xsl:when test="deep-equal($A,$B)"> 
       <xsl:text>DEEP-EQUAL!</xsl:text> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:text>NOT DEEP-EQUAL</xsl:text> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

</xsl:transform> 

E, naturalmente, questa trasformazione ritorna

NOT DEEP-EQUAL 

Ma se si ordina le sequenze prima di loro a confronto, per esempio, con una funzione personalizzata che fa uso di xsl:perform-sort, vedere la relevant part of the specification:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" 
    xmlns:local="www.local.com" extension-element-prefixes="local" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xsl:output method="text"/> 

    <xsl:variable name="A" select="('a','b','c')"/> 
    <xsl:variable name="B" select="('a','c','b')"/> 

    <xsl:template match="/"> 
     <xsl:choose> 
      <xsl:when test="deep-equal(local:sort($A),local:sort($B))"> 
       <xsl:text>DEEP-EQUAL!</xsl:text> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:text>NOT DEEP-EQUAL</xsl:text> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:function name="local:sort" as="xs:anyAtomicType*"> 
     <xsl:param name="in" as="xs:anyAtomicType*"/> 
     <xsl:perform-sort select="$in"> 
      <xsl:sort select="."/> 
     </xsl:perform-sort> 
    </xsl:function> 

</xsl:transform> 

quindi, il risultato sarà

DEEP-EQUAL! 

EDIT: Infatti, set uguaglianza comporterebbe che non solo ordine è irrilevante, ma anche duplicati non dovrebbe fare una differenza. Pertanto, una corretta uguaglianza insieme significherebbe applicare anche distinct-values() alle variabili della sequenza:

<xsl:when test="deep-equal(local:sort(distinct-values($A)),local:sort(distinct-values($B)))">