È possibile utilizzare .querySelector() di HTML per selezionare tramite l'attributo xlink in un SVG?

StackOverflow https://stackoverflow.com//questions/23034283

Domanda

Dato:

<body>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <a xlink:href="url"></a>
    </svg>
</body>

È possibile utilizzare i DOM HTML .querySelector() O .querySelectorAll() per selezionare il collegamento all'interno dell'SVG dal contenuto del suo xlink:href attributo?

Funziona:

document.querySelector('a')                    // <a xlink:href="url"/>

Questi non:

document.querySelector('[href="url"]')         // null
document.querySelector('[xlink:href="url"]')   // Error: not a valid selector
document.querySelector('[xlink\:href="url"]')  // Error: not a valid selector
document.querySelector('[xlink\\:href="url"]') // null

Esiste un modo di scrivere quel selettore di attributi per fargli "vedere" il file xlink:href?

È stato utile?

Soluzione

Selettore di query Potere gestire gli spazi dei nomi, ma diventa complicato perché

  1. La sintassi per specificare gli spazi dei nomi nei selettori CSS è diversa da html;

  2. L'API querySelector non dispone di alcun metodo per assegnare un prefisso dello spazio dei nomi (come xlink) a uno spazio dei nomi effettivo (come "http://www.w3.org/1999/xlink").

Sul primo punto, la parte rilevante delle specifiche CSS consente di specificare NO namespace (predefinito), uno spazio dei nomi specifico o Qualunque spazio dei nomi:

@namespace foo "http://www.example.com";
[foo|att=val] { color: blue }
[*|att] { color: yellow }
[|att] { color: green }
[att] { color: green }

La prima regola corrisponderà solo agli elementi con l'attributo att nel "http://www.esempio.com" spazio dei nomi con il valore "val".

La seconda regola abbinerà solo gli elementi con l'attributo att indipendentemente dallo spazio dei nomi dell'attributo (incluso nessuno spazio dei nomi).

Le ultime due regole sono equivalenti e corrisponderanno solo agli elementi con l'attributo att dove si trova l'attributo non in uno spazio dei nomi.

Guarda questo violino, prestando attenzione agli stili di riempimento (predefinito, passaggio del mouse e attivo):
https://jsfiddle.net/eg43L/

L'API dei selettori adotta la sintassi del selettore CSS, ma non ha equivalenti a quella @namespace regola per definire uno spazio dei nomi.Di conseguenza, i selettori con spazi dei nomi non sono validi Ma il token dello spazio dei nomi con caratteri jolly è valido:

Se il gruppo di selettori include prefissi dello spazio dei nomi che devono essere risolti, l'implementazione deve sollevare un'eccezione SYNTAX_ERR ([DOM-LEVEL-3-CORE], sezione 1.4).

Questa specifica non fornisce supporto per la risoluzione di prefissi di spazi dei nomi arbitrari.Tuttavia, il supporto per un meccanismo di risoluzione del prefisso dello spazio dei nomi potrebbe essere preso in considerazione per l'inclusione in una versione futura di queste specifiche.

È necessario risolvere un prefisso dello spazio dei nomi se il componente dello spazio dei nomi non è vuoto (ad es. |div), che rappresenta lo spazio dei nomi nullo o un asterisco (ad es. *|div), che rappresenta qualsiasi spazio dei nomi. Poiché non è necessario risolvere l'asterisco o il prefisso dello spazio dei nomi vuoto, le implementazioni che supportano la sintassi dello spazio dei nomi nei selettori devono supportarli.

(grassetto aggiunto)

Guardare il violino ancora una volta, questa volta prestando attenzione all'output della console.Il comando document.querySelector('[*|href="#url"]') restituisce l'elemento desiderato.

Un ultimo avvertimento: MDN mi dice che IE8- non supporta gli spazi dei nomi CSS, quindi potrebbe non funzionare per loro.


Aggiornamento 31-01-2015:

Come sottolineato da @ Netsi1964 nei commenti, questo non funziona per gli attributi personalizzati con spazi dei nomi nei documenti HTML 5, poiché HTML non supporta gli spazi dei nomi XML.(Funzionerebbe in un SVG autonomo o in un altro documento XML incluso XHTML.)

Quando il parser HTML5 incontra un attributo come data:myAttribute="value" lo tratta come una singola stringa per il nome dell'attributo, incluso il :.Per rendere le cose più confuse, la stringa viene automaticamente minuscola.

Ottenere querySelector per selezionare questi attributi è necessario includere il file data: come parte della stringa dell'attributo.Tuttavia, dal momento che : ha un significato speciale nei selettori CSS, devi evitarlo con a \ carattere.E poiché hai bisogno di \ per essere superato come parte del selettore, devi scappare Esso nel tuo JavaScript.

La chiamata riuscita quindi si presenta così:

document.querySelector('[data\\:myattribute="value"]');

Per rendere le cose un po' più logiche, consiglierei di utilizzare tutti caratteri minuscoli per i nomi degli attributi, poiché il parser HTML 5 li convertirà comunque.Il browser Blink/Webkit ridurrà automaticamente i selettori in minuscolo che passi querySelector, ma in realtà si tratta di un bug molto problematico (nel senso che non è mai possibile selezionare elementi SVG con nomi di tag composti da maiuscole e minuscole).

Ma la stessa soluzione funziona per xlink:href?NO!Il parser HTML 5 riconosce xlink:href nel markup SVG e lo analizza correttamente come un attributo con spazio dei nomi.

Ecco il violino aggiornato con test aggiuntivi.Ancora una volta, guarda l'output della console per vedere i risultati.Testato su Chrome 40, Firefox 35 e IE 11;l'unica differenza nel comportamento è che Chrome corrisponde al selettore di maiuscole e minuscole.

Altri suggerimenti

Sfortunatamente no.

querySelector non gestisce gli spazi dei nomi XML, quindi non esiste un modo semplice per farlo in questo modo.Puoi comunque usare un file XPath domanda.

var result = document.evaluate(
    // Search for all nodes with an href attribute in the xlink namespace.
    '//*[@xlink:href="url"]',
    document,
    function(prefix){
        return {
            xlink: "http://www.w3.org/1999/xlink"
        }[prefix] || null;
    },
    XPathResult.ORDERED_NODE_ITERATOR_TYPE
);

var element = result.iterateNext();

Se hai bisogno del supporto completo di tutti i browser, come per IE, che non dispone di un file document.evaluate, puoi riempirlo con polyfill malvagio-buono-xpath.

Naturalmente, a seconda del tuo utilizzo, potrebbe essere più semplice farlo (che penso funzionerà su IE):

var element = Array.prototype.filter.call(document.querySelectorAll('a'),
    function(el){
    return el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') === 'url';
})[0] || null;

[*|href] corrisponderà ad entrambi i file html href e Svg xlink:href, quindi utilizzare :not([href]) per escludere html href.

document.querySelectorAll('[*|href]:not([href])')

testato in cromo

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top