通用库的<svg>的setAttributeNS xmlns

时间:2018-09-29 18:06:08

标签: javascript xml dom svg

当浏览器在DOMException元素上使用setAttributeNS来设置<svg>属性时,似乎网络浏览器会抛出xmlns。即

>>> s = document.createElementNS('http://www.w3.org/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.org/2000/svg', 'xmlns', 
      'http://www.w3.org/2000/svg')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

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

Mozilla docs建议始终使用setAttributeNS,但是没有提及这种可能性。因此,该建议似乎有一些警告。

setAttributeNS上的DOM Level 2 spec提供了一些见解:

  

NAMESPACE_ERR:如果qualifiedName格式不正确,qualifiedName具有前缀且namespaceURI为null,qualifiedName具有前缀“ xml”且namespaceURI与“ http://www.w3.org/XML/1998/namespace”不同,则引发此错误,或者如果qualifiedName是“ xmlns”,并且namespaceURI与“ http://www.w3.org/2000/xmlns/”不同。

因此,该特殊异常似乎是可能失败的更广泛案件的一部分。这些情况是什么现在还不清楚。

我正在编写通用Web框架tko / Knockout 4.0,因此它应该支持svg和核心HTML命名空间之外的其他标签。

最常遇到的问题来自xmlns标签上的svg,因此是an issue。我通过专门检查是否已设置xmlns并在这种情况下使用setAttributeworked around this

该解决方法似乎非常具体,我担心一般情况。关于通常如何使用setAttributeNSsetAttribute处理设置属性是否有先例?

其他Web框架不能很好地解决这个问题-它通常与其他逻辑混合在一起。我见过的最即时的提交是针对angular的,但是它并不能直接解决这个问题。

相关:Difference between setAttribute and setAttributeNS(null,

1 个答案:

答案 0 :(得分:1)

它不会涵盖所有情况,但是应该走很长一段路:

const NAMESPACES = {
  svg: 'http://www.w3.org/2000/svg',
  html: 'http://www.w3.org/1999/xhtml',
  xml: 'http://www.w3.org/XML/1998/namespace',
  xlink: 'http://www.w3.org/1999/xlink',
  xmlns: 'http://www.w3.org/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))
    }
  }
}

如果遇到的属性是xmlns="http://www.w3.org/2000/svg",则会将其添加

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

如果遇到的属性是xml:space="preserve"(SVG编辑器众所周知使用的属性),则会将其添加到

.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve')