fn: functions in XPathExpressions cause Exceptions in JDK1.6 - java

I would like to select the value of the first "href" attribute from documents like this using XPath:
<div>
<a href="#a">
<span>foo</span>
</a>
<a href="#b">
<span>bar</span>
</a>
<a href="#c">
<span>baz</span>
</a>
</div>
However, I am only interested in those a elements that govern spans with text content "bar" or "baz". I was hoping that I could achieve that with the following Java code:
Document document = getDocument(); // returns non-null Document
XPath xpath = XPathFactory.newInstance().newXPath();
String href = xpath.evaluate("//a[fn:matches(span, '^ba.$')]/attribute::href", document);
but whenever I'm using one of the fn: functions in an XPathExpression, I get
javax.xml.transform.TransformerException: Unknown error in XPath.
at com.sun.org.apache.xpath.internal.XPath.execute(XPath.java:363)
at com.sun.org.apache.xpath.internal.XPath.execute(XPath.java:301)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.eval(XPathImpl.java:210)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:275)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:365)
at MyCode(MyCode.java:71)
Caused by: java.lang.NullPointerException
at com.sun.org.apache.xpath.internal.functions.FuncExtFunction.execute(FuncExtFunction.java:206)
at com.sun.org.apache.xpath.internal.axes.PredicatedNodeTest.executePredicates(PredicatedNodeTest.java:340)
[...]
Similar Exceptions are thrown when I use fn:starts-with. I'm using JDK 1.6 on GNU/Linux.
Any ideas what I'm doing wrong? Thanks!

These string functions are available in XPath 2.0 which is not supported by the Java XPath API. You will have to use another library like Saxon for evaluating XPath 2.0 expressions:

Only the core xpath functions 1.0 (http://www.w3.org/TR/xpath/#corelib) are supported by default (as stated here: http://download.oracle.com/javase/6/docs/api/javax/xml/xpath/XPathFunctionResolver.html).
Therefore, instead of matches you should use contains (http://www.w3.org/TR/xpath/#function-contains).

First, if you use a prefix (fn) you should bind that to a namespace URI.
Second, XPath 1.0 functions doesn't use a prefix binding. That would be interpreted as a extension function call.
Third, match() is a XPath 2.0 function.
In XPath 1.0, this expression should work:
/div/a[span[starts-with(.,'ba')]][1]/#href
If you use // step operator, you should use:
(//a[span[starts-with(.,'ba')]])[1]/#href

Related

Specifying multiple conditions in xpath

I want to select all the tags with <td class='blob-code blob-code-addition'> and <td class='blob-code blob-code-deletion'> . So I am trying to include or condition here between the two predicates. It does not work. However, if I include only one of the two classes it works . What is the problem here? Something is wrong with the syntax.
By getChanges = By.xpath("//td[#class='blob-code blob-code-addition'] or //td[#class='blob-code blob-code-deletion']");
You want to specify that like the following:
//td[contains(#class,'deletion') or contains(#class,'addition')]
or
//td[contains(#class,'blob-code blob-code-addition') or contains(#class,'blob-code blob-code-deletion')]
If you want to do a tag independent search then you can simply use
//*[contains(#class,'blob-code blob-code-addition') or contains(#class,'blob-code blob-code-deletion')]
From your answer it looks like you are trying to concatenate two different xpaths
However, contians() is not mandatory here. You also can do without this
//*[(#class='blob-code blob-code-addition') or (#class='blob-code blob-code-deletion')]
what works for me is below expression using "|" character inside my expression-
By element = driver.findElement(By.xpath("//button[#clas='xyz'] | //button[#clas='abc']"))
I used above expression for JAVA + Selenium + Maven project
using pom:
#FindBy(xpath ="//span[contains(#class,'vui-menuitem-label-text') and normalize-space(.) = 'Clone']")
To select all the tags with:
<td class="blob-code blob-code-addition">
<td class="blob-code blob-code-deletion">
You can use either of the following Locator Strategies:
Using xpath through class attribute with or clause:
//td[#class='blob-code blob-code-addition' or #class='blob-code blob-code-deletion']
Using xpath through single class attribute with or clause:
//td[contains(#class,'blob-code-addition') or contains(#class,'blob-code-deletion')]
Using xpath through partial class attribute with or clause:
//td[contains(#class,'addition') or contains(#class,'deletion')]
For writing Multiple Xpath in one element selenium
driver.find_elements(By.XPATH, '//div[#class="any-content"]//p|//h3|//figure')
You can write many tags by using "|" modulo.

what causes the org.xml.sax.saxparseexception: already seen doctype

I am using Eclipse to find a specific anchor elements in XML file. The plugin I am using in Eclipse is XPath. When I typed in the element I want to find, it shows:
org.xml.sax.saxparseexception: already seen doctype
<div class="list">
<input name = "abc" type = "hidden" value = "true">
...
and if I want to search all the attribute name. I type in //#name in the expression field. it shows the error warning like that. Did I typed in the wrong expression or any ways find the element? Thanks

Use spring tag in XSLT

I have a XSL/XML parser to produce jsp/html code.
Using MVC model I need to accees spring library in order to perform i18n translation.
Thus, given the xml
<a>
...
<country>EN</country>
...
</a>
and using <spring:message code="table_country_code.EN"/> tag, choose based on the browser language, the transalation into England, Inglaterra, etc...
However, the XSL do not support <spring:message> tag.
The idea is to have a XSLT with something like this
<spring:message code="table_country_code.><xsl:value-of select="country"/>"/>`
to have the final code <spring:message code="table_country_code.EN"/> and be recognized in the final JSP/HTML based on i18n translation.
I also tried to create the spring tag in Java when I make a parse to create the XML but I sill have the same error.
The prefix "spring" for element "spring:message" is not bound.
[EDIT]
I saw some questions here, like using bean:spring but still have the same problem.
any pointers?
XSLT has to be namespace well formed XML, so you need to declare the namespace and you can not use < in attribute values.
Spring 3 - Accessing messages.properties in jsp
suggests the namespace should be
http://www.springframework.org/tags
so presumably you want an XSLT code of
<spring:message
xmlns:spring="http://www.springframework.org/tags"
code="table_country_code.{country}"
/>
where {} is an attribute value template that evaluates the XPath country

JAVA DOM: duplicated attributes

I'm using the DOM library for JAVA and some entries XHTML encounter this problem:
[Fatal Error] tree.xml:238:185: Attribute "itemprop" was already specified for element "span".
This is the XHTML part with problems:
<span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person' itemprop='name'>Rodrigo</span>
Exists some option to allow duplicate attributes in DOM?
Thanks!
My understanding is that the Microdata specification only allows one itemprop per HTML element, meaning that the DOM library you're using is properly marking it as invalid markup. If you want to specify multiple values, they need to be space-separated, like this:
<span class='fn' itemprop='author name' itemscope='itemscope' itemtype='http://schema.org/Person'>Rodrigo</span>
Incidentally, the class attribute works the same way.

Sum values in HTML page using XQuery / XPath 2.0

I have an HTML page like:
<html>
<head><title>Hello</title></head>
<body>
<div id="foo">
<h6>9</h6>
<h6>3</h6>
<h6>5</h6>
</div>
</body>
</html>
I'd like to use XQuery (or xpath 2.0) to sum the values in the <h6> elements. I'm using xmlbeans (with saxon as the engine) and I tried the following which just gives me a null pointer exception;
XmlObject xml = XmlObject.Factory.parse(xmlFile);
XmlCursor htmlCursor = xml.newCursor();
XmlCursor result = htmlCursor.execQuery("sum(for $val in $this//h6 return number($val))");
System.out.println(result.getObject());
Any ideas?
Use the XPath Sum Function:
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile);
XPath path = XPathFactory.newInstance().newXPath();
System.out.println(path.evaluate("sum(//h6)", doc));
prints:
17
I'm guessing here but the $this in your query looks a bit odd. In standard XQuery there is no variable in scope called $this. I assume you want the context item, so your query would look like:
sum(for $val in .//h6 return number($val))
or more simply:
sum(.//h6/number(.))
or just:
sum(.//h6)
Omitting the dot would mean that the XPath starts at the root of the document, not at the context item.

Categories