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

时间:2022-11-19 10:03:45

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?

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

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?

有没有办法编写该属性选择器,使其“看到”xlink:href?

3 个解决方案

#1


36  

Query selector can handle namespaces, but it gets tricky because

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

  1. The syntax for specifying namespaces in CSS selectors is different from html;

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

  2. The querySelector API doesn't have any method for assigning a namespace prefix (like xlink) to an actual namespace (like "http://www.w3.org/1999/xlink").

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

On the first point, the relevant part of the CSS specs allows you to specify no namespace (the default), a specific namespace, or any namespace:

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

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

The first rule will match only elements with the attribute att in the "http://www.example.com" namespace with the value "val".

第一个规则将仅匹配“http://www.example.com”命名空间中具有属性att的元素,值为“val”。

The second rule will match only elements with the attribute att regardless of the namespace of the attribute (including no namespace).

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

The last two rules are equivalent and will match only elements with the attribute att where the attribute is not in a namespace.

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

See this fiddle, paying attention to the fill styles (default, hover, and active):
https://jsfiddle.net/eg43L/

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

The Selectors API adopts the CSS selector syntax, but has no equivalent to the @namespace rule for defining a namespace. As a result, selectors with namespaces are not valid but the wildcard namespace token is valid:

Selectors API采用CSS选择器语法,但没有用于定义命名空间的@namespace规则。因此,具有名称空间的选择器无效,但通配符名称空间标记有效:

If the group of selectors include namespace prefixes that need to be resolved, the implementation must raise a SYNTAX_ERR exception ([DOM-LEVEL-3-CORE], section 1.4).

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

This specification does not provide support for resolving arbitrary namespace prefixes. However, support for a namespace prefix resolution mechanism may be considered for inclusion in a future version of this specification.

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

A namespace prefix needs to be resolved if the namespace component is neither empty (e.g. |div), representing the null namespace, or an asterisk (e.g. *|div), representing any namespace. Since the asterisk or empty namespace prefix do not need to be resolved, implementations that support the namespace syntax in Selectors must support these.

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

(bold added)

Check out the fiddle again, this time paying attention to the console output. The command document.querySelector('[*|href="#url"]') returns the element you want.

再次查看小提琴,这次注意控制台输出。命令document.querySelector('[* | href =“#url”]')返回所需的元素。

One final warning: MDN tells me that IE8- do not support CSS namespaces, so this might not work for them.

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


Update 2015-01-31:

As @Netsi1964 pointed out in the comments, this doesn't work for custom namespaced attributes in HTML 5 documents, since HTML doesn't support XML namespaces. (It would work in a stand-alone SVG or other XML document including XHTML.)

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

When the HTML5 parser encounters an attribute like data:myAttribute="value" it treats that as a single string for the attribute name, including the :. To make things more confusing, it auto-lowercases the string.

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

To get querySelector to select these attributes, you have to include the data: as part of the attribute string. However, since the : has special meaning in CSS selectors, you need to escape it with a \ character. And since you need the \ to get passed through as part of the selector, you need to escape it in your JavaScript.

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

The successful call therefore looks like:

因此成功的电话看起来像:

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

To make things a little more logical, I would recommend using all lower-case for your attribute names, since the HTML 5 parser will convert them anyway. Blink/Webkit browser will auto-lowercase selectors you pass querySelector, but that's actually a very problematic bug (in means you can never select SVG elements with mixed-case tag names).

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

But does the same solution work for xlink:href? No! The HTML 5 parser recognizes xlink:href in SVG markup, and correctly parses it as a namespaced attribute.

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

Here's the updated fiddle with additional tests. Again, look at the console output to see the results. Tested in Chrome 40, Firefox 35, and IE 11; the only difference in behavior is that Chrome matches the mixed-case selector.

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

#2


6  

Unfortunately not.

querySelector doesn't handle XML namespaces, so there is no easy way to do this that way. You can however use an XPath query.

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

If you need full cross-browser support, such as for IE, which does not have a document.evaluate, you can polyfill it with wicked-good-xpath.

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

Of course, depending on your usage, it may be easier to do this (which I think will work on IE):

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

#3


3  

[*|href] will match both html href and svg xlink:href, then use :not([href]) to exclude html href.

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

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

tested in chrome

用铬测试

#1


36  

Query selector can handle namespaces, but it gets tricky because

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

  1. The syntax for specifying namespaces in CSS selectors is different from html;

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

  2. The querySelector API doesn't have any method for assigning a namespace prefix (like xlink) to an actual namespace (like "http://www.w3.org/1999/xlink").

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

On the first point, the relevant part of the CSS specs allows you to specify no namespace (the default), a specific namespace, or any namespace:

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

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

The first rule will match only elements with the attribute att in the "http://www.example.com" namespace with the value "val".

第一个规则将仅匹配“http://www.example.com”命名空间中具有属性att的元素,值为“val”。

The second rule will match only elements with the attribute att regardless of the namespace of the attribute (including no namespace).

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

The last two rules are equivalent and will match only elements with the attribute att where the attribute is not in a namespace.

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

See this fiddle, paying attention to the fill styles (default, hover, and active):
https://jsfiddle.net/eg43L/

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

The Selectors API adopts the CSS selector syntax, but has no equivalent to the @namespace rule for defining a namespace. As a result, selectors with namespaces are not valid but the wildcard namespace token is valid:

Selectors API采用CSS选择器语法,但没有用于定义命名空间的@namespace规则。因此,具有名称空间的选择器无效,但通配符名称空间标记有效:

If the group of selectors include namespace prefixes that need to be resolved, the implementation must raise a SYNTAX_ERR exception ([DOM-LEVEL-3-CORE], section 1.4).

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

This specification does not provide support for resolving arbitrary namespace prefixes. However, support for a namespace prefix resolution mechanism may be considered for inclusion in a future version of this specification.

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

A namespace prefix needs to be resolved if the namespace component is neither empty (e.g. |div), representing the null namespace, or an asterisk (e.g. *|div), representing any namespace. Since the asterisk or empty namespace prefix do not need to be resolved, implementations that support the namespace syntax in Selectors must support these.

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

(bold added)

Check out the fiddle again, this time paying attention to the console output. The command document.querySelector('[*|href="#url"]') returns the element you want.

再次查看小提琴,这次注意控制台输出。命令document.querySelector('[* | href =“#url”]')返回所需的元素。

One final warning: MDN tells me that IE8- do not support CSS namespaces, so this might not work for them.

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


Update 2015-01-31:

As @Netsi1964 pointed out in the comments, this doesn't work for custom namespaced attributes in HTML 5 documents, since HTML doesn't support XML namespaces. (It would work in a stand-alone SVG or other XML document including XHTML.)

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

When the HTML5 parser encounters an attribute like data:myAttribute="value" it treats that as a single string for the attribute name, including the :. To make things more confusing, it auto-lowercases the string.

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

To get querySelector to select these attributes, you have to include the data: as part of the attribute string. However, since the : has special meaning in CSS selectors, you need to escape it with a \ character. And since you need the \ to get passed through as part of the selector, you need to escape it in your JavaScript.

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

The successful call therefore looks like:

因此成功的电话看起来像:

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

To make things a little more logical, I would recommend using all lower-case for your attribute names, since the HTML 5 parser will convert them anyway. Blink/Webkit browser will auto-lowercase selectors you pass querySelector, but that's actually a very problematic bug (in means you can never select SVG elements with mixed-case tag names).

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

But does the same solution work for xlink:href? No! The HTML 5 parser recognizes xlink:href in SVG markup, and correctly parses it as a namespaced attribute.

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

Here's the updated fiddle with additional tests. Again, look at the console output to see the results. Tested in Chrome 40, Firefox 35, and IE 11; the only difference in behavior is that Chrome matches the mixed-case selector.

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

#2


6  

Unfortunately not.

querySelector doesn't handle XML namespaces, so there is no easy way to do this that way. You can however use an XPath query.

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

If you need full cross-browser support, such as for IE, which does not have a document.evaluate, you can polyfill it with wicked-good-xpath.

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

Of course, depending on your usage, it may be easier to do this (which I think will work on IE):

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

#3


3  

[*|href] will match both html href and svg xlink:href, then use :not([href]) to exclude html href.

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

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

tested in chrome

用铬测试