是否可以使用HTML的.querySelector()来通过SVG中的xlink属性进行选择?

时间:2014-04-12 18:17:18

标签: javascript html5 dom svg xlink

假设:

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

是否可以使用HTML DOM .querySelector().querySelectorAll()通过其xlink:href属性的内容选择SVG内的链接?

这有效:

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

这些不是:

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

是否有办法编写该属性选择器以使其“看到&#39; xlink:href

3 个答案:

答案 0 :(得分:39)

查询选择器可以处理名称空间,但是因为

而变得棘手
  1. 在CSS选择器中指定名称空间的语法与html不同;

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

  3. 在第一点上,the relevant part of the CSS specs允许您指定 no 命名空间(默认),特定命名空间或任何命名空间:

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

    第一条规则只匹配&#34; http://www.example.com&#34;中的属性att的元素。名称空间的值为&#34; val&#34;。

         

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

         

    最后两条规则是等效的,只会匹配属性为att的元素,其中属性不是在命名空间中。

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

    Selectors API采用CSS选择器语法,但没有用于定义命名空间的@namespace规则。因此,selectors with namespaces are not valid but the wildcard namespace token is valid

      

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

         

    此规范不支持解析任意名称空间前缀。但是,可以考虑支持名称空间前缀解析机制以包含在本规范的未来版本中。

         

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

    (加粗)

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

    最后一个警告:MDN告诉我IE8-不支持CSS名称空间,所以这可能不适合他们。


    更新2015-01-31:

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

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

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

    因此成功的通话如下:

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

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

    但同样的解决方案适用于xlink:href吗?没有! HTML 5解析器识别SVG标记中的xlink:href,并正确地将其解析为命名空间属性。

    Here's the updated fiddle with additional tests。再次,查看控制台输出以查看结果。在Chrome 40,Firefox 35和IE 11中测试过;行为的唯一区别是Chrome与混合大小写选择器匹配。

答案 1 :(得分:6)

不幸的是没有。

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

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

当然,根据您的使用情况,可能更容易做到这一点(我认为这适用于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;

答案 2 :(得分:4)

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

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

在chrome中测试