How to remove XML namespaces using Javascript?
Asked Answered
B

3

8

I am finding that, for my purposes, XML namespaces are simply causing much headache and are completely unnecessary. (For example, how they complicate xpath.)

Is there a simple way to remove namespaces entirely from an XML document?

(There is a related question, but it deals with removing namespace prefixes on tags, rather than namespace declarations from the document root: "Easy way to drop XML namespaces with javascript".)

Edit: Samples and more detail below:

XML:

<?xml version="1.0" ?>
<main xmlns="example.com">
  <primary>
    <enabled>true</enabled>
  </primary>
  <secondary>
    <enabled>false</enabled>
  </secondary>
</main>

JavaScript:

function useHttpResponse()
{
    if (http.readyState == 4)
    {
        if(http.status == 200)
        {
            var xml = http.responseXML;
            var evalue = getXMLValueByPath('/main/secondary/enabled', xml);
            alert(evalue);
        }
    }
}

function getXMLValueByPath(nodepath, xml)
{
    var result = xml.evaluate(nodepath, xml, null, XPathResult.STRING_TYPE, null).stringValue;
    return result;
}

The sample XML is just like the actual one I am working with, albeit much shorter. Notice that there are no prefixes on the tags for the namespace. I assume this is the null or default namespace.

The JavaScript is a snippet from my ajax functions. If I remove the xmlns="example.com" portion from the main tag, I am able to successfully get the value. As long as any namespace is present, the value becomes undefined.

Edit 2:

It may be worth mentioning that none of the declared namespaces are actually used in the XML tags (like the sample above). In the actual XML file I am working with, three namespaces are declared, but no tags are prefixed with a namespace reference. Thus, perhaps the question should be re-titled, "How to remove unused XML namespaces using Javascript?" I do not see the reason to retain a namespace if it is 1) never used and 2) complicating an otherwise simple path to a node using xpath.

Basidium answered 22/12, 2010 at 0:3 Comment(20)
Namespaces are of no value, right up until they are needed.Jaddan
The irony here is that namespaces were apparently developed to allow duplicate tags and avoid confusion between them. I have duplicate tags with differing parent tags, and am attempting to use xpath to select them. If I remove the namespace declaration manually, it's quite simple to select the elements. With the namespace declaration intact, it fails entirely.Basidium
Why not ask for help with using namespaces instead of giving up?Jaddan
Namespaces shouldn't complicate xpath particularly, you just namespace the parts inside the xpath as you go. Maybe it would be better to figure out why your xpath isn't working, rather than stripping out structural data?Doig
"but it deals with removing namespaces on tags, rather than from the entire document" - can you explain the difference? Do you mean you want to remove namespace declarations? Namespace prefixes? What does it mean to remove namespaces from an entire document other than removing them from tags?Monoacid
Along the lines of what @John Saunders said, if you post your input XML and the XPath that is failing, and the javascript code that's trying to use XPath, we can probably help you work with the namespaces successfully. Yes, they can be a pain to work with until you know how. But they are also a pain to fight against.Monoacid
@John Saunders: Actually, I did here: #4496069 -- unfortunately there wasn't a resolution.Basidium
@LarsH: I wanted to remove the declarations not the prefixes as, in the example I added to the question, there are no prefixes.Basidium
@Erica: I agree, but they seem to be complicating things unnecessarily. I don't foresee namespaces ever being required in my application, which is a document intended to provide sensor variables in a way that they can be viewed using an ajax-enabled web app.Basidium
@JYelton: I added a comment to your previous question. You didn't really provide enough information about the reason to remove namespaces.Jaddan
@John Saunders: I added the same examples to the previous question along with a description of what's happening with and without the namespace declaration. Your first comment, regarding namespaces having no value until needed, is accurate: Currently, I do not need them, therefore they have no value. (In fact, are being detrimental.) This arose because the library being used to generate the XML document requires that a namespace be present. Prior to usage of this library, the XML did not have namespace declarations and pulling data from it via AJAX was much simpler.Basidium
@LarsH: I edited my wording of the reference to the related question, for clarity.Basidium
@JY: "Your first comment, regarding namespaces having no value until needed, is accurate: Currently, I do not need them, therefore they have no value." Note the difference between "needed" and "I ... need them". If you have a standard vocabulary, and you don't need the namespace but others do, does that mean namespaces are unneeded?Monoacid
@JY: if you want to take a stab at making it work as designed, try passing a namespace resolver as the 3rd argument to evaluate(). See w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator-evaluate and developer.mozilla.org/en/… for pointers.Monoacid
@LarsH: I was able to get a namespace resolver to work (in #4496069). Prior to the solution given in that question, the namespace resolver and its syntax were not working for me (I did not understand how to get values for tags in the default namespace when a namespace is declared but never used). I decided it would be easier to just remove the namespace entirely (why have it if it is unused?). That is the reason this question was asked, and it may still be useful to know how to remove such namespaces.Basidium
@Monoacid / John Saunders: I've added a note to the question which may or may not help: the fact that none of the declared namespaces are actually used in the XML tags.Basidium
@JYelton: I'm confused by the statement that the namespaces are "not used" as in your sample. In your sample, a default namespace is declared on the outermost element, and therefore it is used on all unprefixed elements in the document.Monoacid
@LarsH: None of the elements are prefixed with a namespace reference (for example <ex:primary>) though, by asking me this question, I believe I now understand that all child elements of the outermost element inherit its namespace even without explicitly refering to it by prefix. Still, it eludes me, of what use is a single namespace? If two or more are present, the ability to categorize elements is beneficial. Perhaps I will pose that as a separate question, but first - apparently I must read up more on XML! Thanks for your help.Basidium
@JY - you're welcome. Again, even when elements of a particular NS are not mixed with those of another in your document, that does not mean the NS is not of use; 1) in other documents, those elements can be mixed with those of other NS's, so what would you do, have two versions of every element, one in the namespace of that vocabulary and one in no namespace? That would complicate the standard; and 2) even when unmixed with other NS's, requiring the elements to be in a certain NS helps with validation.Monoacid
@JY - anyway, yes you are right about the child elements inheriting the default namespace.Monoacid
G
6

This should remove any namespace declaration you find:

var xml = http.responseXML.replace(/<([a-zA-Z0-9 ]+)(?:xml)ns=\".*\"(.*)>/g, "<$1$2>");
Grisgris answered 24/12, 2010 at 18:33 Comment(7)
Results in Javascript console error: http.responseXML.replace is not a function.Basidium
@JY: you could force this to work by converting responseXML to a string before calling the replace() method. But it's not robust, since you're not really parsing the XML. @andre: are you sure that regex is correct? Can you explain the [a-zA-Z0-9 ]+?Monoacid
That regex is correct. The part that you mention simply grabs the tag name and the space that follows, so, in <rootnode xmlns="some.domain.name" attribute="value"> it would replace it with <rootnode attribute="value">.Grisgris
@LarsH: Converting it to a string is certainly an option, to make the replace function work. However, it would need to be converted back to XML. I need suggestions on how to do that (recreate the XML document with some sort of string parse?).Basidium
@andre: it looks to me like you want the space to be after the ]+, not intermixed multiple times with the alphanumerics of the tag name. Also the regex would at best replace only a default namespace declaration, not all namespace declarations. But that may be all that @Basidium needs...Monoacid
Probably want to do the replace on responseText not responseXML (save the conversion). Still needs to be loaded into an XML doc to be useful though. There has to be a better way.Vickery
If you want to reduce the star height of the pattern, and also to avoid removing trailing attributes, always use ? after the *: <([a-zA-Z0-9 ]+)(?:xml)ns=\".*?\"(.*?)>. This worked for me. The original regex will strip out any attributes that comes after the xmlns attribute, which might not be what you want.Chandra
M
4

Inorder to replace all the xmlns attributes from an XML javascript string

you can try the following regex

xmlns=\"(.*?)\"

NB: This regex can be used to replace any attributes

var str = `<?xml version="1.0" ?>
<main xmlns="example.com">
  <primary>
    <enabled>true</enabled>
  </primary>
  <secondary>
    <enabled>false</enabled>
  </secondary>
</main>`;

str = str.replace(/xmlns=\"(.*?)\"/g, '');

console.log(str)
Maniemanifest answered 12/10, 2017 at 6:27 Comment(0)
B
0

Approach without using regex (This removes attributes also)

let xml = '';//input
let doc = new DOMParser().parseFromString(xml,"text/xml");
var root=doc.firstElementChild;
var newdoc = new Document();
newdoc.appendChild(removeNameSpace(root));
function removeNameSpace (root){    
    let parentElement = document.createElement(root.localName);
    let nodeChildren = root.childNodes;
    for (let i = 0; i <nodeChildren.length; i++) {
        let node = nodeChildren[i];
        if(node.nodeType == 1){
            let child
            if(node.childElementCount!=0)
                child = removeNameSpace(node);
            else{
                child = document.createElement(node.localName);
                let textNode = document.createTextNode(node.innerHTML);
                child.append(textNode);
            }
            parentElement.append(child);
        }
    }
    return parentElement;
}
Bronchopneumonia answered 14/11, 2022 at 5:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.