最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - setAttributeNS xmlns of <svg> for a general-purpose library - Stack Overflow

programmeradmin0浏览0评论

It appears web browsers throw a DOMException when one uses setAttributeNS on a <svg> element to set the xmlns attribute. i.e.

>>> s = document.createElementNS('', 'svg')
<svg>​</svg>​

>>> s.setAttributeNS(null, 'xmlns', '123')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

>>> s.setAttributeNS('', 'xmlns', 
      '')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

>>> s.setAttributeNS(null, 'xmlns', '')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

The Mozilla docs remend always using setAttributeNS, however it makes no mention of this possibility. So the remendation appears to have caveats.

The DOM Level 2 spec on setAttributeNS gives some insight:

NAMESPACE_ERR: Raised if the qualifiedName is malformed, if the qualifiedName has a prefix and the namespaceURI is null, if the qualifiedName has a prefix that is "xml" and the namespaceURI is different from "", or if the qualifiedName is "xmlns" and the namespaceURI is different from "/".

So this particular exception appears to be part of a broader set of cases that could fail. It's not immediately apparent what those cases are.

I'm writing tko / Knockout 4.0, a general-purpose web framework, and so it should support svg and other tags outside the core HTML namespace.

The most encountered problem es from xmlns on svg tags so it's an issue. I've worked around this by specifically checking to see if xmlns is being set and using setAttribute in that case.

That workaround seems quite specific and I'm concerned about the general case. Is there a precedent for how to generally handle setting attributes with setAttributeNS and setAttribute?

The other web frameworks don't address this neatly — it's generally mixed with other logic; the most on-point mit I've seen is for angular, but it's not directly addressing this problem.

Related: Difference between setAttribute and setAttributeNS(null,

It appears web browsers throw a DOMException when one uses setAttributeNS on a <svg> element to set the xmlns attribute. i.e.

>>> s = document.createElementNS('http://www.w3/2000/svg', 'svg')
<svg>​</svg>​

>>> s.setAttributeNS(null, 'xmlns', '123')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

>>> s.setAttributeNS('http://www.w3/2000/svg', 'xmlns', 
      'http://www.w3/2000/svg')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

>>> s.setAttributeNS(null, 'xmlns', 'http://www.w3/2000/svg')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

The Mozilla docs remend always using setAttributeNS, however it makes no mention of this possibility. So the remendation appears to have caveats.

The DOM Level 2 spec on setAttributeNS gives some insight:

NAMESPACE_ERR: Raised if the qualifiedName is malformed, if the qualifiedName has a prefix and the namespaceURI is null, if the qualifiedName has a prefix that is "xml" and the namespaceURI is different from "http://www.w3/XML/1998/namespace", or if the qualifiedName is "xmlns" and the namespaceURI is different from "http://www.w3/2000/xmlns/".

So this particular exception appears to be part of a broader set of cases that could fail. It's not immediately apparent what those cases are.

I'm writing tko / Knockout 4.0, a general-purpose web framework, and so it should support svg and other tags outside the core HTML namespace.

The most encountered problem es from xmlns on svg tags so it's an issue. I've worked around this by specifically checking to see if xmlns is being set and using setAttribute in that case.

That workaround seems quite specific and I'm concerned about the general case. Is there a precedent for how to generally handle setting attributes with setAttributeNS and setAttribute?

The other web frameworks don't address this neatly — it's generally mixed with other logic; the most on-point mit I've seen is for angular, but it's not directly addressing this problem.

Related: Difference between setAttribute and setAttributeNS(null,

Share Improve this question edited Sep 29, 2018 at 19:07 Brian M. Hunt asked Sep 29, 2018 at 18:06 Brian M. HuntBrian M. Hunt 83.9k76 gold badges234 silver badges349 bronze badges 8
  • When I create an SVG I use var svg = document.createElementNS(ns.svg, "svg"); where ns.svg: "http://www.w3/2000/svg" – enxaneta Commented Sep 29, 2018 at 18:37
  • Wouldn't it be better to force pliance to the spec and set the xmlns namespaceURI if it's encountered - and, for the same reason, set the xml namespaceURI if it has been used as a prefix? – ccprog Commented Sep 29, 2018 at 18:43
  • @ccprog TKO does indeed set the xmlns according to the spec, and that is the better approach, but that does not solve the problem. – Brian M. Hunt Commented Sep 29, 2018 at 18:45
  • i.e. document.createElementNS('http://www.w3/2000/svg', "svg").setAttributeNS(null, 'xmlns', '...') throws – Brian M. Hunt Commented Sep 29, 2018 at 18:46
  • What I meant was, in the method you quoted, something like var ns = name === 'xmlns' ? 'http://www.w3/2000/xmlns/' : null; node.setAttributeNS(ns, name, String(value)) – ccprog Commented Sep 29, 2018 at 18:51
 |  Show 3 more ments

1 Answer 1

Reset to default 7

It will not cover all cases, but this should go a long way:

const NAMESPACES = {
  svg: 'http://www.w3/2000/svg',
  html: 'http://www.w3/1999/xhtml',
  xml: 'http://www.w3/XML/1998/namespace',
  xlink: 'http://www.w3/1999/xlink',
  xmlns: 'http://www.w3/2000/xmlns/' // sic for the final slash...
}

class JsxObserver extends LifeCycle {
  ...

  setNodeAttribute (node, name, valueOrObservable) {
    const value = unwrap(valueOrObservable)
    NativeProvider.addValueToNode(node, name, valueOrObservable)
    if (value === undefined) {
      node.removeAttributeNS(null, name)
    } else if (isThenable(valueOrObservable)) {
      Promise.resolve(valueOrObservable)
        .then(v => this.setNodeAttribute(node, name, v))
    } else {
      const [prefix, ...unqualifiedName] = name.split(':')
      let ns = null
      if (prefix === 'xmlns' || unqualifiedName.length && NAMESPACES[prefix]) {
        ns = NAMESPACES[prefix]
      }
      node.setAttributeNS(ns, name, String(value))
    }
  }
}

If the attribute encountered is xmlns="http://www.w3/2000/svg", it will be added with

.setAttributeNS('http://www.w3/2000/xmlns/', 'xmlns', 'http://www.w3/2000/svg')

If the attribute encountered is xml:space="preserve" (something that SVG editors notoriously use), it will be added with

.setAttributeNS('http://www.w3/XML/1998/namespace', 'xml:space', 'preserve')
发布评论

评论列表(0)

  1. 暂无评论