0

I have this code for removing unwanted items from xml list, based on their child's attributes.

var xmlDoc=loadXMLDoc(filePath);

var unwanted = xmlDoc.querySelectorAll("item > KlasId[id='1']");
Array.prototype.map.call(unwanted, function(element){
    element.parentNode.parentNode.removeChild(element.parentNode);
});

This works just fine and removes all the item nodes with KlasId children of id=1.

What i want now is to remove items based on KlasId value instead of attribute (for example value 101010), but it somehow doesnt work:

var unwanted = xmlDoc.querySelectorAll("item > KlasId[value='101010']");
etc...

My XML:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<dataroot>
<item>
<KlasId id='1'>101010</KlasId>
</item>

<item>
<KlasId id='2'>101010</KlasId>
</item>

<item>
<KlasId id='3'>202020</KlasId>
</item>
</dataroot>

EDIT:

function loadXMLDoc(filename)
{
if (window.XMLHttpRequest)
  {
  xhttp=new XMLHttpRequest();
  }
else // code for IE5 and IE6
  {
  xhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xhttp.open("GET",filename,false);
xhttp.send();
return xhttp.responseXML;
}
JLRishe
  • 99,490
  • 19
  • 131
  • 169
devbull
  • 227
  • 1
  • 4
  • 16
  • What's `loadXMLDoc`? https://code.google.com/p/dingweiwang/downloads/detail?name=loadXMLDoc.js&can=2&q= maybe? – Sergiu Paraschiv Mar 12 '15 at 09:27
  • loadXMLDoc loads the xml. It works just fine. – devbull Mar 12 '15 at 09:30
  • Are you doing this in a browser, or something like Node? – JLRishe Mar 12 '15 at 09:31
  • Yeah, that's not what I asked. Does not matter, you are next using `querySelectorAll` so I'm guessing `loadXMLDoc` returns a DOM document. `querySelectorAll` accepts CSS selectors. There is no CSS selector for selecting by node value. What you are trying to do is not possible this way. Read this: http://stackoverflow.com/questions/4811962/how-to-css-select-element-based-on-inner-html (You need custom JS. jQuery has a `contains` selector for example specifically for this). – Sergiu Paraschiv Mar 12 '15 at 09:31
  • @JLRishe browser (Chrome) , SergiuParaschiv, sorry, check my edit. – devbull Mar 12 '15 at 09:34

2 Answers2

2

If you are only using Chrome (or Firefox, Opera, or Safari), then you can use XPath to perform this selection:

var found = xmlDoc.evaluate("/*/item[KlasId = '101010']", xmlDoc);

This will return a node iterator that you can use to iterate through the nodes as described here.

function getNodes(iterator) {
    var nodes = [],
        next = iterator.iterateNext();

    while (next) {
        nodes.push(next);
        next = iterator.iterateNext();
    }
    return nodes;
}

getNodes(found).forEach(function (node) {
    node.parentNode.removeChild(node);
});

var xmlDoc = $.parseXML("<dataroot><item><KlasId id='1'>101010</KlasId></item><item><KlasId id='2'>101010</KlasId></item><item><KlasId id='3'>202020</KlasId></item></dataroot>");

var found = xmlDoc.evaluate("//item[KlasId = '101010']", xmlDoc);

function getNodes(iterator) {
    var nodes = [],
        next = iterator.iterateNext();

    while (next) {
        nodes.push(next);
        next = iterator.iterateNext();
    }
    return nodes;
}

getNodes(found).forEach(function (node) {
    console.log('Removing node.');
    node.parentNode.removeChild(node);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>

Internet Explorer does not support .evaluate() (or any XPath functionality as far as I can tell), so if you need cross-browser support, I think you'll need to use a third party library. I recommend xpath.js, on which I am a contributor.

One more option is to use jQuery's extended CSS selectors to perform the selection:

var $nodes = $(xmlDoc).find('item > KlasId:contains("101010")');

$nodes.remove();

var xmlDoc = $.parseXML("<dataroot><item><KlasId id='1'>101010</KlasId></item><item><KlasId id='2'>101010</KlasId></item><item><KlasId id='3'>202020</KlasId></item></dataroot>");

var $nodes = $(xmlDoc).find('item > KlasId:contains("101010")');

console.log($nodes.length);

$nodes.remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>

This is also a cross-browser solution, but it will select the elements based on a contains comparison rather than an equality comparison.

Unrelated side note: .map() is intended for projecting one array onto another. To just carry out a series of side effects, use .forEach().

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • I dont need cross browser, its for personal use, altering big existing xml files for my needs. – devbull Mar 12 '15 at 09:41
  • JLRishe, one additional question. How is with inverse selection? In my old code i used :not operator. Should this be handled inside xpath expression itself or is there any other solution? – devbull Mar 12 '15 at 11:02
  • @devbull XPath should be able to handle it. Could you give an example? – JLRishe Mar 12 '15 at 11:05
  • for example: all item nodes NOT including KlasId with values 101010 and 303030. – devbull Mar 12 '15 at 11:07
  • @devbull `/*/item[KlasId != '101010' and KlasId != '303030']` – JLRishe Mar 12 '15 at 11:10
1

You can't do it with CSS only, because there is no CSS selector to select by the value of the element. See this blogpost about it: Blog

NDY
  • 3,527
  • 4
  • 48
  • 63