Reputation: 173
I have this xml code:
<osm>
<count>
<tag k="nodes" v="608"/>
</count>
<node>
<tag k="addr:housenumber" v="5-10"/>
<tag k="addr:postcode" v="BA1 2BX"/>
</node>
<way>
<tag k="amenity" v="nightclub"/>
<tag k="facebook" v="https://www.facebook.com"/>
</way>
<node>
<tag k="amenity" v="cafe"/>
<tag k="addr:postcode" v="BS3 2BX"/>
</node>
<node>
<tag k="amenity" v="school"/>
<tag k="facebook" v="https://www.facebook.com"/>
</node>
<way>
<tag k="amenity" v="church"/>
<tag k="addr:postcode" v="BAX 5RT"/>
</way>
</osm>
I need to remove all nodes below <osm>
which contain a <tag>
node with the attribute k
with the value 'addr:postcode'
:
<osm>
<count>
<tag k="nodes" v="608"/>
</count>
<way>
<tag k="amenity" v="nightclub"/>
<tag k="facebook" v="https://www.facebook.com"/>
</way>
<node>
<tag k="amenity" v="school"/>
<tag k="facebook" v="https://www.facebook.com"/>
</node>
</osm>
I've tried many permutations around this query, but it returns every occurrence of <tag>
:
<xsl:apply-templates select="osm/*/tag[not(@k='addr:postcode')]">
I assume I need to find the parent, but that's where my knowledge runs out.
Upvotes: 1
Views: 1775
Reputation: 2583
Here is xpath to select all nodes under osm
that doesn't include specific tag:
//osm/*[not(.//tag[@k='addr:postcode'])]
Here is some important note for not()
placement:
to search for element that doesn't include child element (any levels below) use pattern:
//element[not(.//child)]
please note that locator:
//element[.//child[not(@id=1)]]
will select all elements that includes at least 1 child with id != 1.
So in example:
<row class="row1">
<cell id=1/>
<cell id=2/>
<cell id=3/>
</row>
<row class="row2">
<cell id=1/>
<cell id=2/>
</row>
<row class="row3">
<cell id=1/>
<cell id=2/>
</row>
<row class="row4">
<cell id=3/>
</row>
//row[not(.//cell[@id=3])]
will select rows 2 and 3 (rows that doesn't include cell with id=3)
//row[.//cell[not(@id=3)]]
will select rows 1, 2 and 3, but NOT 4 (rows that has at least one cell with id other than 3)
So it's important where you place not()
statement, as it could totally change XPath logic.
Upvotes: 1
Reputation: 52858
You're right; you need to select the parent of tag
. To do that, just select *
and put the tag
in the predicate.
Example...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="osm">
<xsl:copy>
<xsl:apply-templates select="*[not(tag/@k='addr:postcode')]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Working demo here: http://xsltransform.net/pNmBy23
Alternatively, you can add a matching template instead...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[tag/@k='addr:postcode']"/>
</xsl:stylesheet>
This will produce the same output. (http://xsltransform.net/pNmBy23/1)
Upvotes: 3