如何在javascript中为默认命名空间中的XML节点分配前缀?

时间:2017-01-09 23:13:57

标签: javascript xml

我有一个使用jQuery parseXML解析的XML片段。大多数节点没有前缀,它们在默认命名空间中,有些具有前缀。

我需要将默认命名空间中的所有节点与前缀相关联。我已经确保这个前缀已经在XML的字符串版本中声明,并带有一个神奇的字符串替换(即在我加载XML时在根级别声明xmlns:my="http://mydefaulns.com"。)

我尝试了以下内容:

var defaultNs="http://mydefaulns.com";
var xmlDoc = $.parseXML(stringXML);
$(xmlDoc).find("*").each(function() {
    if (this.namespaceURI=== defaultNs) {
        this.prefix = "my";
    }
}

但它没有影响,当我写回来时,仍然没有前缀。

我还尝试加载XML并调用:

xmlDoc.firstChild.removeAttribute("xmlns")

但该属性未被删除,因此前缀未被神奇地更新。

此时,我认为获得我想要的结果的唯一方法是使用新的前缀名称重新创建所有节点,复制所有属性。

这看起来非常极端,还有另一种方式吗?

输入(字符串):

<abc xmlns="http://mydefaulns.com" xmlns:my="http://mydefaulns.com"xmlns:other="http://other.com">
    <node1>Value</node1>
    <other:node2>Value2</other:node2>
</abc>

期望的输出:

<my:abc xmlns:my="http://mydefaulns.com"xmlns:other="http://other.com">
    <my:node1>Value</my:node1>
    <other:node2>Value2</other:node2>
</my:abc>

实际的XML更复杂,但这给了你一个想法。

我用jQuery.parse解析XML,然后使用

返回字符串版本
function XMLDocumentToString(oXML) {
    if (typeof oXML.xml != "undefined") {
       return oXML.xml;
    } else if (XMLSerializer) {
        return (new XMLSerializer().serializeToString(oXML));
    } else {
        throw "Unable to serialize the XML";
    }    
 }

3 个答案:

答案 0 :(得分:5)

无需解析xml字符串,只需使用replaceregular expressions一样:

var prefix = "my:";
stringXML = stringXML.replace(/(<\/?)(\w+)(?!:)(\b)/g, "$1" + prefix + "$2$3");

这将匹配<</之后的任何字母序列(有效标记名称)(<是必需的,/是可选的),而不是后跟:但后跟\b

&#13;
&#13;
var stringXML = '<abc xmlns="http://mydefaulns.com" xmlns:my="http://mydefaulns.com" xmlns:other="http://other.com"><node1>Value</node1><other:node2>Value2</other:node2></abc>';

console.log("BEFORE: ", stringXML);

var prefix = "my:";
stringXML = stringXML.replace(/(<\/?)(\w+)(?!:)(\b)/g, "$1" + prefix + "$2$3");

console.log("AFTER: ", stringXML);
&#13;
&#13;
&#13;

答案 1 :(得分:3)

  

此时,我认为获得我想要的结果的唯一方法是使用新的前缀名称重新创建所有节点,复制所有属性。

是的,如果你想要干净利落的话,这正是你必须要做的。

使用正则表达式的解决方案很脆弱。这是你给出的例子:

listenTo

现在考虑以下文档,它与原始文档相同:

<abc xmlns="http://mydefaulns.com" xmlns:my="http://mydefaulns.com" xmlns:other="http://other.com">
    <node1>Value</node1>
    <other:node2>Value2</other:node2>
</abc>

唯一改变的是命名空间<abc xmlns="http://mydefaulns.com" xmlns:my="http://mydefaulns.com"> <node1>Value</node1> <node2 xmlns="http://other.com">Value2</node2> </abc> 中的元素node2如何被赋予命名空间。在原始文档中,它是通过http://other.com前缀,它是在根节点上定义的。这是通过重新定义other上的默认命名空间。从XML的角度来看,这两个文件是相同的。如何定义node2的命名空间并不重要。但问题是,你得到的两个基于正则表达式的答案都不能正确转换这个文档。

这是一个操作DOM树以产生最终结果的实现:

node2
var stringXML = '<abc xmlns="http://mydefaulns.com" xmlns:my="http://mydefaulns.com" xmlns:other="http://other.com">\n\
    <node1>Value</node1>\n\
    <other:node2>Value2</other:node2>\n\
</abc>';

var defaultNS = "http://mydefaulns.com";
var xmlDoc = $.parseXML(stringXML);

xmlDoc.firstChild.removeAttribute("xmlns");

// Make sure we do have xmlns:my defined.
xmlDoc.firstChild.setAttribute("xmlns:my",defaultNS);

function transformChildren(parent) {
  // We take a copy of childNodes before clearing it.
  var childNodes = Array.prototype.slice.call(parent.childNodes);

  while (parent.firstChild) {
    parent.removeChild(parent.firstChild);
  }

  var newChild;
  var limit = childNodes.length;
  for (var childIx = 0; childIx < limit; ++childIx) {
    newChild = undefined;
    var node = childNodes[childIx];
    if (node.nodeType === Node.ELEMENT_NODE && node.namespaceURI === defaultNS) {
      newChild = xmlDoc.createElementNS(defaultNS, "my:" + node.tagName);

      // Copy the attributes.
      var attributes = node.attributes;
      for (var attrIx = 0; attrIx < attributes.length; ++attrIx) {
        var attr = attributes[attrIx];
        newChild.setAttributeNS(attr.namespaceURI, attr.name, attr.value)
      }

      // Move the children.
      while (node.firstChild) {
        newChild.appendChild(node.firstChild);
      }
      
      transformChildren(newChild);
    }
    
    parent.appendChild(newChild || node);
  }
}

transformChildren(xmlDoc);

// This is just reused from the question.
function XMLDocumentToString(oXML) {
  if (typeof oXML.xml != "undefined") {
    return oXML.xml;
  } else if (XMLSerializer) {
    return (new XMLSerializer().serializeToString(oXML));
  } else {
    throw "Unable to serialize the XML";
  }
}

console.log(XMLDocumentToString(xmlDoc));

答案 2 :(得分:1)

这可能会对你有所帮助

var inputXmlText='<abc xmlns="http://mydefaulns.com" xmlns:my="http://mydefaulns.com" xmlns:other="http://other.com"><node1>Value</node1><other:node2>Value2</other:node2></abc>'
var inputXml=jQuery.parseXML(inputXmlText);
var list=[];
var prefix="my";

$(inputXml).find("*").each(function(){
  if(this.tagName.indexOf(":")<0){
     inputXmlText=inputXmlText.replace(new RegExp("<" + this.tagName,'g') ,"<"+prefix+":" + this.tagName);
     inputXmlText=inputXmlText.replace(new RegExp("</" + this.tagName,'g') ,"</"+prefix+":" + this.tagName);  
  } 
});

console.log(inputXmlText);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>