As I was experimenting with some XPath SVG paths while answering another question about Selenium, I found out a strange behaviour with XPath on Chrome (I didn't try on some other browsers).
On http://www.amcharts.com/svg-maps/?map=usa, why doesn't that XPath work?
//*[@id="chartdiv"]/div/div[1]/svg/g[7]/g/g[1]
Whereas this one does?
//*[@id="chartdiv"]/div/div[1]/*[name()="svg"]/*[name()="g"][7]/*[name()="g"]/*[name()="g"][2]
I had to make the following changes:
/g
becomes /*[name()="g"]
/svg
becomes /*[name()="svg"]
/path
becomes /*[name()="path"]
The weird thing is that I got the first XPath by right-clicking the element HTML and copied the XPath from there.
I have another example on http://gmsgroup.com/municenter.asp where:
//*[@id='ext-gen203']/*[name()='svg']/*[name()='a']/*[name()='path'][starts-with(@d, 'M136.65')]/..
works,//*[@id='ext-gen203']/*[name()='svg']/*[name()='a'][@title='Hawaii']
doesn't.Here, /*[name()='a'][@title='Hawaii']
couldn't get <a title="Hawaii"></a>
, why?
Namespaces can either be prefixed:
<root xmlns:ns="www.example.com"/>
or default namespaces:
<root xmlns="www.example.com"/>
SVG is in a default namespace. A path expression like /svg
tells an XPath processor to look for an element that is called "svg" and that is in no namespace whatsoever. Therefore, this expression only matches:
<svg/> or <svg xmlns=""/>
Using /*[name()='svg']
does only rule out a prefixed namespace. It still allows for an element that is called "svg" and that is in a default namespace, without a prefix. This second expression matches
<svg xmlns="http://www.w3.org/2000/svg"/>
but not
<ns:svg xmlns:ns="http://www.w3.org/2000/svg"/>
To prove this, consider the following XSLT stylesheet:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="*[name() ='svg']">
<hit/>
</xsl:template>
</xsl:transform>
Applied to the following input, a shortened SVG document:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"/>
Results in:
<?xml version="1.0" encoding="UTF-8"?>
<hit/>
See for yourself online here.
EDIT (responding to your comment)
More clearly, does it mean that the SVG default namespace overrides the one from the page and therefore doesn't handle expressions such as [@title='Hawaii']?
The HTML elements themselves do not have a namespace - and SVG does not "override" the page's namespace. The default namespace on the svg
element only applies to itself and all child elements (including the a[@title='Hawaii']
element inside it.
//*[@id='ext-gen203']/*[name()='svg']/*[name()='a'][@title='Hawaii']
should be able to find the a
element and I am very surprised it does not.
Where to find the specification for that default namespace?
If you mean default namespaces in general, look here: http://www.w3.org/TR/REC-xml-names/#scoping-defaulting. If you meant the SVG specification, study the following chapter of the SVG specification: http://www.w3.org/TR/SVG/struct.html.
Does it also mean that there isn't a better way of getting than //[@id='ext-gen203']/[name()='svg']/[name()='a']/[name()='path'][starts-with(@d, 'M136.65')]/..?
The better way to do this is to register or declare those namespaces and thereby make them available for use in Xpath expressions by means of prefixes (as Martin Honnen has pointed out). Chrome Dev Tools is not my field of expertise, I cannot comment on how to do it there.
HTML5 and text/html allows you to mix HTML, MathML and SVG elements in one document and does not require you to use the namespaces associated with the different vocabularies. With XPath however you need to make sure you bind a prefix to the SVG namespace and use that prefix in your queries as in the DOM tree the SVG elements are in a different namespace than the HTML elements. Whether that is possible inside the developer tool I don't know but with an API there are usually ways to set up a namespace resolver that maps prefixes you want to use in your XPath expressions to namespace URLs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With