48

Given:

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

Is it possible to use the HTML DOM's .querySelector() or .querySelectorAll() to select the link inside the SVG by the contents of its xlink:href attribute?

This works:

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

These don't:

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

Is there a way of writing that attribute selector to make it 'see' the xlink:href?

4

3 回答 3

56

查询选择器可以处理命名空间,但它变得很棘手,因为

  1. 在 CSS 选择器中指定命名空间的语法与 html 不同;

  2. querySelector API 没有任何将命名空间前缀(如xlink)分配给实际命名空间(如"http://www.w3.org/1999/xlink")的方法。

在第一点,CSS 规范的相关部分允许您指定命名空间(默认)、特定命名空间或任何命名空间:

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

第一条规则将仅匹配atthttp://www.example.com ”命名空间中属性值为“val”的元素。

第二条规则将只匹配具有属性的元素,att而不管属性的命名空间(包括没有命名空间)。

最后两个规则是等效的,并且将仅匹配具有该属性不在att命名空间中的属性的元素。

看到这个小提琴,注意填充样式(默认、悬停和活动):
https ://jsfiddle.net/eg43L/

Selectors API 采用 CSS 选择器语法,但没有等同@namespace于定义命名空间的规则。结果,具有命名空间的选择器无效,但通配符命名空间令牌有效

如果选择器组包含需要解析的命名空间前缀,则实现必须引发 SYNTAX_ERR 异常([DOM-LEVEL-3-CORE],第 1.4 节)。

本规范不支持解析任意命名空间前缀。然而,对命名空间前缀解析机制的支持可能会考虑包含在本规范的未来版本中。

|div如果命名空间组件既不是空的(例如)(表示空命名空间),也不是星号(例如*|div)(表示任何命名空间),则需要解析命名空间前缀。由于不需要解析星号或空命名空间前缀,因此支持选择器中命名空间语法的实现必须支持这些。

(加粗)

再次检查小提琴,这次注意控制台输出。该命令document.querySelector('[*|href="#url"]')返回您想要的元素。

最后一个警告:MDN告诉我 IE8- 不支持 CSS 命名空间,所以这可能对他们不起作用。


2015 年 1 月 31 日更新:

正如@Netsi1964 在评论中指出的那样,这不适用于 HTML 5 文档中的自定义命名空间属性,因为 HTML 不支持 XML 命名空间。(它适用于独立的 SVG 或其他 XML 文档,包括 XHTML。)

当 HTML5 解析器遇到类似的属性data:myAttribute="value"时,它会将其视为属性名称的单个字符串,包括:. 为了让事情变得更加混乱,它会自动小写字符串。

querySelector选择这些属性,您必须包含data:作为属性字符串的一部分。但是,由于:在 CSS 选择器中具有特殊含义,您需要使用\字符对其进行转义。并且由于您需要\作为选择器的一部分传递,因此您需要在 JavaScript 中 对其进行转义。

因此,成功的调用如下所示:

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

为了使事情更合乎逻辑,我建议您对属性名称使用全部小写,因为 HTML 5 解析器无论如何都会转换它们。Blink/Webkit 浏览器将自动小写您传递的选择器querySelector,但这实际上是一个非常有问题的错误(意味着您永远不能选择具有混合大小写标签名称的 SVG 元素)。

但是相同的解决方案是否适用xlink:href?不!HTML 5 解析器识别xlink:hrefSVG 标记,并将其正确解析为命名空间属性。

这是带有附加测试的更新小提琴。同样,查看控制台输出以查看结果。在 Chrome 40、Firefox 35 和 IE 11 中测试;行为上的唯一区别是 Chrome 匹配大小写混合选择器。

于 2014-04-13T20:13:05.027 回答
12

[*|href]将匹配 htmlhref和 svg xlink:href,然后用于:not([href])排除 html href

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

在铬中测试

于 2016-10-10T07:57:35.130 回答
7

不幸的是没有。

querySelector不处理 XML 命名空间,因此没有简单的方法可以做到这一点。但是,您可以使用XPath查询。

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

如果您需要完整的跨浏览器支持,例如 IE,它没有document.evaluate,您可以使用wicked-good-xpath对其进行 polyfill 。

当然,根据您的使用情况,这样做可能更容易(我认为这将适用于 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;
于 2014-04-12T18:30:27.570 回答