Ist es möglich, HTMLs .querySelector() zu verwenden, um in einer SVG-Datei nach dem xlink-Attribut auszuwählen?

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

Frage

Gegeben:

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

Ist es möglich, die HTML-DOMs zu verwenden? .querySelector() oder .querySelectorAll() um den Link innerhalb der SVG anhand seines Inhalts auszuwählen xlink:href Attribut?

Das funktioniert:

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

Dies gilt nicht:

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

Gibt es eine Möglichkeit, diesen Attributselektor so zu schreiben, dass er das „sieht“. xlink:href?

War es hilfreich?

Lösung

Abfrageselektor dürfen Behandeln Sie Namespaces, aber es wird schwierig, weil

  1. Die Syntax zum Angeben von Namespaces in CSS-Selektoren unterscheidet sich von HTML;

  2. Die querySelector-API verfügt über keine Methode zum Zuweisen eines Namespace-Präfixes (wie xlink) zu einem tatsächlichen Namespace (wie "http://www.w3.org/1999/xlink").

Zum ersten Punkt: der relevante Teil der CSS-Spezifikationen ermöglicht Ihnen die Angabe NEIN Namespace (Standard), ein bestimmter Namespace oder beliebig Namensraum:

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

Die erste Regel gleicht nur Elemente mit dem Attribut ab att im "http://www.example.com" Namespace mit dem Wert „val“.

Die zweite Regel gleicht nur Elemente mit dem Attribut ab att unabhängig vom Namensraum des Attributs (einschließlich keinem Namensraum).

Die letzten beiden Regeln sind gleichwertig und stimmen nur mit Elementen mit dem Attribut überein att wo das Attribut ist nicht in einem Namensraum.

Sehen Sie sich diese Geige an und achten Sie dabei auf die Füllstile (Standard, Hover und Aktiv):
https://jsfiddle.net/eg43L/

Die Selectors-API übernimmt die CSS-Selektorsyntax, hat jedoch kein Äquivalent dazu @namespace Regel zum Definieren eines Namensraums.Infolge, Selektoren mit Namespaces sind ungültig Aber Das Platzhalter-Namespace-Token ist gültig:

Wenn die Gruppe von Selektoren Namespace-Präfixe enthält, die aufgelöst werden müssen, muss die Implementierung eine SYNTAX_ERR-Ausnahme auslösen ([DOM-LEVEL-3-CORE], Abschnitt 1.4).

Diese Spezifikation bietet keine Unterstützung für die Auflösung beliebiger Namespace-Präfixe.Allerdings kann die Unterstützung eines Namensraum-Präfix-Auflösungsmechanismus für die Aufnahme in eine zukünftige Version dieser Spezifikation in Betracht gezogen werden.

Ein Namespace-Präfix muss aufgelöst werden, wenn die Namespace-Komponente weder leer ist (z. B. |div), der den Null-Namespace darstellt, oder ein Sternchen (z. B. *|div), der einen beliebigen Namespace darstellt. Da das Sternchen- oder leere Namespace-Präfix nicht aufgelöst werden muss, müssen Implementierungen, die die Namespace-Syntax in Selectors unterstützen, diese unterstützen.

(fett hinzugefügt)

Kasse die Geige Wieder einmal, diesmal mit besonderem Augenmerk auf die Konsolenausgabe.Der Befehl document.querySelector('[*|href="#url"]') gibt das gewünschte Element zurück.

Eine letzte Warnung: MDN sagt mir, dass IE8 keine CSS-Namespaces unterstützt, daher funktioniert dies möglicherweise nicht für sie.


Update 31.01.2015:

Wie @Netsi1964 in den Kommentaren betonte, funktioniert dies nicht für benutzerdefinierte Namespace-Attribute in HTML 5-Dokumenten, da HTML keine XML-Namespaces unterstützt.(Es würde in einem eigenständigen SVG-Dokument oder einem anderen XML-Dokument einschließlich XHTML funktionieren.)

Wenn der HTML5-Parser auf ein Attribut wie data:myAttribute="value" es behandelt dies als eine einzelne Zeichenfolge für den Attributnamen, einschließlich der :.Um die Sache noch verwirrender zu machen, wird die Zeichenfolge automatisch in Kleinbuchstaben geschrieben.

Zu bekommen querySelector Um diese Attribute auszuwählen, müssen Sie Folgendes einschließen data: als Teil der Attributzeichenfolge.Da jedoch die : Hat in CSS-Selektoren eine besondere Bedeutung, müssen Sie es mit a maskieren \ Charakter.Und da Sie das brauchen \ Um als Teil des Selektors durchgereicht zu werden, müssen Sie entkommen Es in Ihrem JavaScript.

Der erfolgreiche Aufruf sieht also so aus:

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

Um die Sache etwas logischer zu gestalten, würde ich empfehlen, für Ihre Attributnamen ausschließlich Kleinbuchstaben zu verwenden, da der HTML 5-Parser sie ohnehin konvertiert.Der Blink/Webkit-Browser schreibt die von Ihnen übergebenen Selektoren automatisch in Kleinbuchstaben querySelector, aber das ist tatsächlich ein sehr problematischer Fehler (bedeutet, dass Sie niemals SVG-Elemente mit Tag-Namen in Groß- und Kleinschreibung auswählen können).

Aber funktioniert die gleiche Lösung für? xlink:href?NEIN!Der HTML 5-Parser erkennt xlink:href im SVG-Markup und analysiert es korrekt als Namespace-Attribut.

Hier ist die aktualisierte Geige mit zusätzlichen Tests.Schauen Sie sich erneut die Konsolenausgabe an, um die Ergebnisse zu sehen.Getestet in Chrome 40, Firefox 35 und IE 11;Der einzige Unterschied im Verhalten besteht darin, dass Chrome mit dem Selektor für gemischte Groß- und Kleinschreibung übereinstimmt.

Andere Tipps

Leider nicht.

querySelector verarbeitet keine XML-Namespaces, daher gibt es keine einfache Möglichkeit, dies auf diese Weise zu tun.Sie können jedoch eine verwenden XPath Abfrage.

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();

Wenn Sie vollständige browserübergreifende Unterstützung benötigen, z. B. für den IE, der über keine verfügt document.evaluate, Sie können es mit Polyfill füllen wicked-good-xpath.

Abhängig von Ihrer Verwendung kann es natürlich einfacher sein, dies zu tun (was meiner Meinung nach im IE funktionieren wird):

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] passt zu beiden HTML-Dateien href und SVG xlink:href, dann benutze :not([href]) HTML ausschließen href.

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

Getestet in Chrom

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top