XML DOM – Attr 对象(属性节点)
Attr(属性节点)是 XML DOM 中代表元素属性的专用节点类型。尽管它在现代 JavaScript 中不推荐直接操作(推荐用 getAttribute / setAttribute),但理解它的存在和特性非常重要,尤其是在遍历 attributes 集合、处理命名空间、序列化、调试时。
1. 基本信息
| 项目 | 值/说明 |
|---|---|
| nodeType | 2(Node.ATTRIBUTE_NODE) |
| nodeName | 属性名(带前缀时包含前缀,如 xlink:href) |
| nodeValue | 属性值(字符串) |
| textContent | 等同于 nodeValue |
| value | 等同于 nodeValue(Attr 独有,最常用) |
| name | 等同于 nodeName |
| ownerElement | 所属的 Element 对象(非常有用) |
| specified | 布尔值,true 表示显式设置(历史遗留,几乎恒为 true) |
2. 命名空间相关属性(关键!)
| 属性 | 说明 | 示例 |
|---|---|---|
| localName | 不带前缀的本地名称 | href |
| prefix | 命名空间前缀(可能为 null) | xlink |
| namespaceURI | 命名空间 URI(可能为 null) | http://www.w3.org/1999/xlink |
| ownerDocument | 所属文档 |
示例:
<book xmlns:xlink="http://www.w3.org/1999/xlink"
id="b1"
xlink:href="details.xml">
</book>
const book = doc.querySelector("book");
const attr = book.attributes.getNamedItem("xlink:href"); // 或 book.getAttributeNode("xlink:href")
console.log(attr.name); // "xlink:href"
console.log(attr.localName); // "href"
console.log(attr.prefix); // "xlink"
console.log(attr.namespaceURI); // "http://www.w3.org/1999/xlink"
console.log(attr.value); // "details.xml"
console.log(attr.ownerElement === book); // true
3. 如何获取 Attr 对象(4 种方式)
const el = doc.documentElement;
// 1. 最常用:通过 attributes NamedNodeMap
const attr1 = el.attributes["id"]; // 推荐
const attr2 = el.attributes.getNamedItem("id");
// 2. 传统方法(已不推荐)
const attr3 = el.getAttributeNode("id"); // 即将废弃
// 3. 带命名空间
const attr4 = el.attributes.getNamedItemNS(
"http://www.w3.org/2000/xmlns/", "xlink"
);
4. 创建和设置 Attr 对象(不推荐,但可行)
// 方法1:createAttribute(不带命名空间)
const attr = doc.createAttribute("data-custom");
attr.value = "123";
el.setAttributeNode(attr); // 添加到元素
// 方法2:createAttributeNS(带命名空间,推荐用于 xmlns、xlink 等)
const xlink = doc.createAttributeNS(
"http://www.w3.org/2000/xmlns/",
"xmlns:xlink"
);
xlink.value = "http://www.w3.org/1999/xlink";
el.setAttributeNodeNS(xlink);
强烈建议:直接使用 setAttribute() / setAttributeNS(),不要手动创建 Attr。
5. 实际用途场景(Attr 对象真正有用的地方)
| 场景 | 为什么需要 Attr 对象而不是 getAttribute? |
|---|---|
| 遍历所有属性(包括命名空间声明) | element.attributes 返回所有 Attr |
| 精确控制属性顺序(部分 XML 工具在意顺序) | NamedNodeMap 可以 insertBefore |
| 复制属性到另一个元素 | newEl.setAttributeNode(oldAttr.cloneNode()) |
| 调试/序列化时查看原始属性信息 | Attr 包含 namespaceURI、prefix 等完整信息 |
示例:复制所有属性(包括 xmlns 声明)
function copyAttributes(fromEl, toEl) {
for (let attr of fromEl.attributes) {
// 自动处理普通属性和 xmlns 声明
toEl.setAttributeNode(attr.cloneNode());
}
}
6. 现代推荐做法 vs 传统 Attr 操作(对比表)
| 操作 | 现代推荐方式(优先) | 老方式(不推荐) | 说明 |
|---|---|---|---|
| 获取属性值 | el.getAttribute(“id”) | el.getAttributeNode(“id”).value | 更简单 |
| 设置属性 | el.setAttribute(“id”, “123”) | let a=doc.createAttribute(“id”); a.value=”123″; el.setAttributeNode(a) | 太繁琐 |
| 删除属性 | el.removeAttribute(“id”) | el.removeAttributeNode(attr) | |
| 检查是否存在 | el.hasAttribute(“id”) | el.attributes.getNamedItem(“id”) != null | |
| 遍历所有属性 | for(let attr of el.attributes) | 同左 | 现代方式更优雅 |
7. 关键结论(务必记住)
- 99% 的情况下,你不需要直接操作 Attr 对象,用
getAttribute / setAttribute就够了。 - 唯一必须用 Attr 的场景:遍历
element.attributes(尤其是要保留 xmlns、xsi:schemaLocation 等命名空间声明时)。 - Attr 节点不属于文档树的子节点(不在 childNodes 中),它是元素的“附属品”。
- Attr 节点是可以被多个元素共享的(除非你克隆),但现代浏览器通常会自动隔离。
总结一句话:
Attr 对象是 XML DOM 中“属性”的真实节点表示,主要用于
element.attributes遍历和精确复制命名空间声明,日常增删改查请直接使用setAttribute / getAttribute / removeAttribute即可。
掌握这一点,你就不会在处理 xmlns、xsi:schemaLocation、xml:base 等特殊属性时掉坑里了。