![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Keep it simple! Here is a Node.js module to remove unnecessary XML nodes that match given XPath expressions. It uses xpath and xmldom under the hood.
Command-line usage – Node API – Examples – Working with namespaces
Install with $ npm install filterxml -g
and then:
$ filterxml -e pattern -n prefix=namespaceURI input.xml output.xml
For example, remove Style
and StyleMap
from a Keyhole Markup Language document with:
$ filterxml --exclude kml:Style --exclude kml:StyleMap \
--namespace kml=http://www.opengis.net/kml/2.2 \
source.kml simplified.kml
Specify multiple patterns and namespaces with additional -e, --exclude
and -n, --namespace
flags. See filterxml --help
for details.
Install with $ npm install filterxml
and then:
> const filterxml = require('filterxml')
> filterxml(xmlIn, patterns, namespaces, function (err, xmlOut) { ... })
Where
xmlIn
is a string representing the input XML document.patterns
is an array of XPath expressions, like 'book', '/bookstore/book', or '//html:title'. The matching XML nodes will be removed.namespaces
is a map from prefixes to namespace URIs, for example { html: 'http://www.w3.org/TR/html4/' }
xmlOut
is a string representing the filtered output XML document.Common XPath expressions to match nodes include:
x:book
to match all book nodes under a namespace associated with the x
prefix in namespaces
.x:bookstore/x:book
to match all books directly under a bookstore.x:bookstore//x:book
to match all books somewhere under a bookstore.x:bookstore/x:book[1]
to match the first book directly under a bookstore.book
to match all book nodes that are not under a namespace. This is a quite rare situation in real-world XML documents.Internally, filterxml depends on xmldom that respects the standard Web API XMLSerializer. The serializer can sometimes produce unexpected results:
<circle />
will be converted to begin and end tags like <circle></circle>
.<meta />
are preserved but will lose the space before the slash like <meta/>
.Let us filter out all book
nodes:
const xmlIn = '<bookstore>' +
'<book>Animal Farm</book>' +
'<book>Nineteen Eighty-Four</book>' +
'<essay>Reflections on Writing</essay>' +
'</bookstore>'
filterxml(xmlIn, ['book'], {}, function (err, xmlOut) {
if (err) { throw err }
console.log(xmlOut)
})
Outputs:
<bookstore><essay>Reflections on Writing</essay></bookstore>
Let us remove Style tags from a Keyhole Markup Language (KML) file:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Awesome locations</name>
<Style id="s_ylw-pushpin060">
<IconStyle>
<scale>1.1</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
</Icon>
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
</IconStyle>
<PolyStyle>
<fill>0</fill>
</PolyStyle>
</Style>
<Placemark>
<name>Reykjavik</name>
<Point>
<coordinates>-21.933333,64.133333,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
We read the file, filter it, and save the result. Note how we must add a namespace prefix into our pattern to match nodes under the namespace defined in kml
node. Note also how we must associate any used prefix with a namespace URI.
const filterxml = require('filterxml')
const fs = require('fs')
const xmlIn = fs.readFileSync('./norway.kml')
const patterns = ['x:Style']
const namespaces = {
x: 'http://www.opengis.net/kml/2.2'
}
filterxml(xmlIn, patterns, namespaces, function (err, xmlOut) {
if (err) { throw err }
fs.writeFileSync('./norway-simplified.kml', xmlOut)
})
The resulting norway-simplified.kml
:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Awesome locations</name>
<Placemark>
<name>Reykjavik</name>
<Point>
<coordinates>-21.933333,64.133333,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
Often XML documents specify multiple namespaces. For example:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
<Point>
<gx:drawOrder>1</gx:drawOrder>
<coordinates>25.59176188650433,45.6493071755744,0</coordinates>
</Point>
</kml>
To match and remove the gx:drawOrder
node we can not just filterxml(xmlIn, ['gx:drawOrder'], {}, callback)
. The callback would receive an error No namespace associated with prefix gx in gx:drawOrder
. Instead, we must specify what the prefix gx
in our XPath pattern means. It misleadingly looks like it has already been specified in the kml
tag. We cannot blindly trust it. This is because the same prefix can map to different namespace URI in different part of the document:
<?xml version="1.0" encoding="UTF-8"?>
<mymap>
<Places xmlns:kml="http://www.opengis.net/kml/2.2">
<kml:Placemark>
<kml:name>A place described with OpenGIS markup</kml:name>
</kml:Placemark>
</Places>
<Cities xmlns:kml="http://www.google.com/kml/ext/2.2">
<kml:Placemark>
<kml:name>A place described with Google's KML markup</kml:name>
</kml:Placemark>
</Cities
</mymap>
Therefore we must always specify the prefixes we use in our XPath patterns. To remove gx:drawOrder
the following is a valid approach. Note that we can use whatever prefix we want as long as we associate it with a correct namespace URI.
const patterns = ['foo:drawOrder']
const namespaces = { foo: 'http://www.google.com/kml/ext/2.2' }
filterxml(xmlIn, patterns, namespaces, function (err, xmlOut) {
...
})
The snippet above results with xmlOut
equal to:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
<Point>
<coordinates>25.59176188650433,45.6493071755744,0</coordinates>
</Point>
</kml>
So, always declare your prefixes!
[2.0.0] - 2024-03-14
Likely you do not need to make any changes to your code. However, ensure you are running filterxml on Node.js 12.x or later.
FAQs
Remove XML nodes that match given XPath expressions
We found that filterxml demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.