Below is my element hierarchy. How to check (using XPath) that AttachedXml element is present under CreditReport of Primary Consumer
<Consumers xmlns="http://xml.mycompany.com/XMLSchema">
<Consumer subjectIdentifier="Primary">
<DataSources>
<Credit>
<CreditReport>
<AttachedXml><![CDATA[ blah blah]]>
Use the boolean() XPath function
The boolean function converts its
argument to a boolean as follows:
a number is true if and only if
it is neither positive or negative
zero nor NaN
a node-set is true if and only if
it is non-empty
a string is true if and only if
its length is non-zero
an object of a type other than
the four basic types is converted to a
boolean in a way that is dependent on
that type
If there is an AttachedXml in the CreditReport of primary Consumer, then it will return true().
boolean(/mc:Consumers
/mc:Consumer[#subjectIdentifier='Primary']
//mc:CreditReport/mc:AttachedXml)
The Saxon documentation, though a little unclear, seems to suggest that the JAXP XPath API will return false when evaluating an XPath expression if no matching nodes are found.
This IBM article mentions a return value of null when no nodes are matched.
You might need to play around with the return types a bit based on this API, but the basic idea is that you just run a normal XPath and check whether the result is a node / false / null / etc.
XPathFactory xpathFactory = XPathFactory.newInstance(NamespaceConstant.OBJECT_MODEL_SAXON);
XPath xpath = xpathFactory.newXPath();
XPathExpression expr = xpath.compile("/Consumers/Consumer/DataSources/Credit/CreditReport/AttachedXml");
Object result = expr.evaluate(doc, XPathConstants.NODE);
if ( result == null ) {
// do something
}
Use:
boolean(/*/*[#subjectIdentifier="Primary"]/*/*/*/*
[name()='AttachedXml'
and
namespace-uri()='http://xml.mycompany.com/XMLSchema'
]
)
Normally when you try to select a node using xpath your xpath-engine will return null or equivalent if the node doesn't exists.
xpath: "/Consumers/Consumer/DataSources/Credit/CreditReport/AttachedXml"
If your using xsl check out this question for an answer:
xpath find if node exists
take look at my example
<tocheading language="EN">
<subj-group>
<subject>Editors Choice</subject>
<subject>creative common</subject>
</subj-group>
</tocheading>
now how to check if creative common is exist
tocheading/subj-group/subject/text() = 'creative common'
hope this help you
If boolean() is not available (the tool I'm using does not) one way to achieve it is:
//SELECT[#id='xpto']/OPTION[not(not(#selected))]
In this case, within the /OPTION, one of the options is the selected one. The "selected" does not have a value... it just exists, while the other OPTION do not have "selected". This achieves the objective.
Related
public WebElement findChildByXpath(WebElement parent, String xpath) {
loggingService.timeMark("findChildByXpath", "begin. Xpath: " + xpath);
String parentInnerHtml = parent.getAttribute("innerHTML"); // Uncomment for debug purpose.
WebElement child = parent.findElement(By.xpath(xpath));
String childInnerHtml = child.getAttribute("innerHTML"); // Uncomment for debug purpose.
return child;
}
The problem with this code is that childInnerHtml gives me wrong result. I scrape numbers and they are equal.
I even suppose that my code is equal to driver.findElement(By.xpath.
Could you tell me whether my comment really finds a child or what to correct?
Child XPath need to be a relative XPath. Normally this means the XPath expression is started with a dot . to make this XPath relative to the node it applied on. I.e. to be relative to the parent node. Otherwise Selenium will search for the given xpath (the parameter you passing to this method) starting from the top of the entire page.
So, if for example, the passed xpath is "//span[#id='myId']" it should be ".//span[#id='myId']".
Alternatevely you can add this dot . inside the parent.findElement(By.xpath(xpath)); line to make it
WebElement child = parent.findElement(By.xpath("." + xpath));
But passing the xpath with the dot is more simple and clean way. Especially if the passed xpath is come complex expression like "(//div[#class='myClass'])[5]//input" - in this case automatically adding a dot before this expression may not work properly.
<xxx1 xmlns="hello">
<xxx2>
<xxx3>
<name>rule_1</name>
</xxx3>
</xxx2>
</xxx1>
I select node by "//*[namespace-uri()='hello']/*[local-name()='name']"
It should get //hello:xxx1/xxx2/xxx3/name , and it does.
Now I try to get element . In reality, I don't know how much parent for <name> will get <xxx1>;
I try this code
node.getParent().getNamespaceURI() = "Hello"
and increase getParent() amount to get <xxx1>
But the first time I call <xxx3>.getNamespaceURI() it returns true.
Is the namespace inherited?
How to get the element has or not has xmlns?
Sorry for my question was not clearly.
I'm trying to get the element which is the first declared namespace "hello".
<xxx1 xmlns="hello">
<xxx2>
<xxx3>
this three node which one is contained xmlns="hello", 'cause <xxx2> and <xxx3> was not declare xmlns in the label.
Hello and Welcome to Stack Overflow!
Yes, namespaces are sort of inherited, but the terminology normally used is that, in your example, the <name> element is in the scope of the namespace declaration xmlns="hello", so the <name>element will be in the hello namespace.
With DOM4J, you can test whether an element is in a namespace or not like this:
boolean hasNamespace(Element e) {
return e.getNamespaceURI().length() > 0;
}
If the element is not in any namespace, getNamespaceURI() returns an empty string.
I guess that you want to select the <name> element, but you don't know at which level it be, i.e. how many parents it will have. You can always use this XPath expression:
Node node = doc.selectSingleNode("//*[namespace-uri() = 'foo' and local-name() = 'name']");
I'm using the S9API with Saxon 9.7 HE, and I have a NodeInfo object. I need to create an xPath statement that uniquely corresponds to this NodeInfo. It's easy enough to get the prefix, the node name, and the parent:
String prefix = node.getPrefix();
String localPart = node.getLocalPart();
NodeInfo parent = node.getParent();
So I can walk up the tree, building the xPath as I go. But what I can't find is any way to get the positional predicate info. IOW, it's not sufficient to create:
/persons/person/child
because it might match multiple child elements. I need to create:
/persons/person[2]/child[1]
which will match only one child element. Any ideas on how to get the positional predicate info? Or maybe there's a better way to do this altogether?
BTW, for those who use the generic DOM and not the S9API, here's an easy solution to this problem: http://practicalxml.sourceforge.net/apidocs/net/sf/practicalxml/DomUtil.html#getAbsolutePath(org.w3c.dom.Element)
Edit: #Michael Kay's answer works. To add some meat to it:
XPathExpression xPathExpression = xPath.compile("./path()");
List matches = (List) xPathExpression.evaluate(node, XPathConstants.NODESET);
String pathToNode = matches.get(0).toString();
// If you want to remove the expanded QName syntax:
pathToNode = pathToNode.replaceAll("Q\\{.*?\\}", "");
This must be done using the same xPath object that was previously used to acquire the NodeInfo object.
In XPath 3.0 you can use fn:path().
Earlier Saxon releases offer saxon:path().
The challenge here is handling namespaces. fn:path() returns a path that's not sensitive to namespace-prefix bindings by using the new expanded-QName syntax
/Q{}persons/Q{}person[2]/Q{}child[1]
Does anybody have an idea how to find out whether an element contains <![CDATA[ text ]]> or not ? I search through the dom4j API and Jaxen and I can't find how to do that... If I retrieve the text, it the cdata wrapper is trimmed.
The method:
Node.asXML()
returns the entire element with its value unmodified by anything.
So if you have:
<nodes>
<node><![CDATA[value]]></node>
</nodes>
Calling the text methods will return "value", but calling "asXML()" will return:
<node><![CDATA[value]]></node>
From there, I guess you can do a String search for the CDATA tag.
Technically you can still do this.
public boolean isCDATA(org.dom4j.Node node) {
for (org.dom4j.Node n : node.content()) {
if (org.w3c.dom.Node.CDATA_SECTION_NODE == n.getNodeType()) {
return true;
}
}
return false;
}
http://dom4j.sourceforge.net/dom4j-1.6.1/apidocs/org/dom4j/Node.html#getNodeType%28%29
will this work?
public short getNodeType()
Returns the code according to the type of node. This makes processing nodes polymorphically much easier as the switch statement can be used instead of multiple if (instanceof) statements.
Returns: a W3C DOM complient code for the node type such as ELEMENT_NODE or ATTRIBUTE_NODE
I have this matlab function:
function trackName = getTrackName(xpath, gpxSourceDom)
% Import the XPath classes
import javax.xml.xpath.*
% Compile the expression
expression = xpath.compile('gpx/trk/name');
% Apply the expression to the DOM.
trackNames = expression.evaluate(gpxSourceDom, XPathConstants.NODESET);
end
I need a way to print every element inside trackNames NODESET. How can I do that?
A quick search of MATLAB and xpath returned this result:
using xpath in matlab
The part you're missing is iterating through the results and displaying the name. For more ideas of what you can do with the nodes, check out the javadoc.
for i = 1:nodeList.getLength
node = nodeList.item(i-1);
disp(char(node.getFirstChild.getNodeValue))
end