How can I get H1,H2,H3 contents in one single xpath expression?
I know I could do this.
//html/body/h1/text()
//html/body/h2/text()
//html/body/h3/text()
and so on.
Use:
/html/body/*[self::h1 or self::h2 or self::h3]/text()
The following expression is incorrect:
//html/body/*[local-name() = "h1"
or local-name() = "h2"
or local-name() = "h3"]/text()
because it may select text nodes that are children of unwanted:h1, different:h2, someWeirdNamespace:h3.
Another recommendation: Always avoid using // when the structure of the XML document is statically known. Using // most often results in significant inefficiencies because it causes the complete document (sub)tree roted in the context node to be traversed.
Related
I'm trying to select all elements using XSL and XPath syntax where there is more than one pickup. I'd like to return the counter_name for each. Can someone please help me with the syntax? In this example there is only one counter_name with pickup locations, but there could be multiple locations where there are pickup counters.
XPATH
<xsl:value-of select="results/unique_locations/partner_location_ids[count(pickup) > 0]/counter_name" /><br/>
XML
<results>
<unique_locations>
<counter_name>Lake Buena Vista, FL</counter_name>
<is_airport>N</is_airport>
<partner_location_ids>
<pickup>
</pickup>
<dropoff>
<container>ZR-ORLS001</container>
<container>ET-ORLR062</container>
<container>HZ-ORLS011</container>
<container>HZ-ORLW015</container>
<container>AV-ORLR004</container>
</dropoff>
</partner_location_ids>
<counter_name>Orlando, FL</counter_name>
<is_airport>N</is_airport>
<partner_location_ids>
<pickup>
<container>ET-ORLC037</container>
<container>AV-ORLC021</container>
<container>ET-ORLC033</container>
<container>ET-ORLC035</container>
<container>HZ-ORLS007</container>
<container>HZ-ORLC004</container>
<container>HZ-ORLC002</container>
<container>ZR-ORLS002</container>
<container>BU-ORLE002</container>
<container>AV-ORLC019</container>
<container>ET-ORLR064</container>
<container>ET-ORLC001</container>
<container>ET-ORLR063</container>
<container>ET-ORLR061</container>
<container>HZ-ORLC011</container>
<container>HZ-ORLC054</container>
<container>HZ-ORLN003</container>
<container>HZ-ORLC007</container>
<container>HZ-ORLC005</container>
<container>ZA-ORLC002</container>
<container>ZA-ORLC003</container>
<container>ZA-ORLC001</container>
<container>AV-ORLC002</container>
<container>AV-ORLC001</container>
<container>BU-ORLS001</container>
<container>ET-ORLC012</container>
<container>AL-ORLR071</container>
<container>HZ-ORLC022</container>
<container>ET-ORLC051</container>
<container>HZ-ORLC025</container>
<container>HZ-ORLN018</container>
<container>HZ-ORLC017</container>
<container>AV-ORLN003</container>
<container>BU-ORLC002</container>
<container>BU-ORLC003</container>
<container>BU-ORLS006</container>
<container>ET-ORLC027</container>
<container>ET-ORLC022</container>
<container>AL-ORLR081</container>
<container>BU-ORLC005</container>
<container>HZ-ORLR029</container>
<container>HZ-ORLC032</container>
<container>HZ-ORLC031</container>
<container>HZ-ORLC030</container>
<container>ET-ORLC021</container>
</pickup>
<dropoff>
<container>HZ-ORLC003</container>
<container>ZA-ORLC004</container>
<container>BU-ORLW002</container>
<container>HZ-ORLC026</container>
<container>ZR-ORLC010</container>
<container>AL-ORLR073</container>
</dropoff>
</partner_location_ids>
</unique_locations>
Your XML structure is non-ideal, in that it appears to contain elements that are associated with each other by sequence, rather than exclusively by containment within the same element. But XPath can deal with that.
Supposing that the context node for evaluation of the XPath is the parent node of the <results> whose contents you are examining, it appears you want something along these lines:
results/unique_locations/partner_location_ids[pickup/*]/preceding-sibling::counter_name
Note in the first place the predicate: [pickup/*]. The expression within, interpreted in boolean context, evaluates to true if the expression matches any nodes. That's why we need pickup/*, not just pickup, to distinguish between <pickup> elements that contain child nodes and those that don't.
Additionally, observe the use of the preceding-sibling axis instead of the default child axis to step from each matching <partner_location_ids> to its corresponding (I think) <counter_name>.
I've below xml and would like to read the value of 'Value' tag whose Name matches 'test2'. I'm using the below xpath , but did not work. Can someone help.
/*[ local-name()='OutputData']/*[ local-name()='OutputDataItem']/*[ local-name()='Name'][normalize-space(.) = 'test2']//*[local-name()='Value']/text()
<get:OutputData>
<get:OutputDataItem>
<get:Name>test1</get:Name>
<get:Value/>
</get:OutputDataItem>
<get:OutputDataItem>
<get:Name>test2</get:Name>
<get:Value>B5B4</get:Value>
</get:OutputDataItem>
<get:OutputDataItem>
<get:Name>test3</get:Name>
<get:Value/>
</get:OutputDataItem>
<get:OutputDataItem>
<get:Name>OP_VCscEncrptCd_VAR</get:Name>
<get:Value/>
</get:OutputDataItem>
</get:OutputData>
Thanks
You were close, but because the get:name and get:value are siblings, you need to adjust your XPath a little.
Your XPath was attempting to address get:value elements that were descendants of get:name, rather than as siblings. Move the criteria that is filtering the get:name into a predicate, then step down into the get:value:
/*[ local-name()='OutputData']/*[ local-name()='OutputDataItem']
[*[ local-name()='Name'][normalize-space(.) = 'test2']]/*[local-name()='Value']/text()
You could also combine the criteria of the predicate filter on the get:name and use an and:
/*[ local-name()='OutputData']/*[ local-name()='OutputDataItem']
[*[ local-name()='Name' and normalize-space(.) = 'test2']]/*[local-name()='Value']/text()
This should work I think:
//*[local-name()="get:Name" and text()="test2"]/following-sibling::*[local-name()="get:Value"]/text()
My problem is the following :
I usually have those data:
<structures>
<structure id="10">
<code>XXX</code>
</structure>
</structures>
so the table I display (single columns : code) is ok.
But in some cases, the data is the result a a query with no content, so the data is:
<structures/>
resulting in my table not displaying + error.
I am trying to insert, in the case of an empty instance, a single node so that the data would look like:
<structures>
<structure id="0"/>
</structures>
I am trying something like that :
<xforms:action ev:event="xforms-submit-done">
<xforms:insert if="0 = count(instance('{./instance-name}')/root/node())" context="instance('{./instance-name}')/root/node()" origin="xforms:element('structure', '')" />
</xforms:action>
but no node inserted when I look at the data in the inspector in the page.
Any obvious thing I am doing wrong?
There seems to be erros in your XPath if and context expressions:
if="0 = count(instance('{./instance-name}')/root/node())"
context="instance('{./instance-name}')/root/node()"
You are a using curly brackets { and }, I assume to have the behavior of attribute value templates (AVTs). But the if and context expressions are already XPath expressions, so you cannot use AVTs in them. Try instead:
if="0 = count(instance(instance-name)/root/node())"
context="instance(instance-name)/root/node()"
Also, the instance-name path is relative to something which might not be clear when reading or writing the expression. I would suggest using an absolute path for example instance('foo')/instance-name to make things clearer.
You don't provide the structure of the other instances, so I can tell for sure, but you'll expression above suppose that they have the form:
<xf:instance id="foo">
<some-root-element>
<root>
<structure/>
</root>
<some-root-element>
</xf:instance>
I don't know if that's what you intend.
Finally, you could replace count(something) = 0, with empty(something).
I am using HtmlAgilityPack to try to find HTML 'A' nodes that have a href attribute that contains a certain string, in my case the string '/groups/':
HtmlNodeCollection groups = source.DocumentNode.SelectNodes("//a[contains(#href, '/groups/')]");
Although the source code contains about 20 such nodes my code above is returning none which leads me to believe maybe I'm doing it incorrectly.
Is what I'm doing correct, and if not how can I select nodes that have a certain attribute that has a value that contains a certain string?
Your expression is seems to be correct as for me.
You don't post your source document (or at least a part of it). So, I'll be guessing.
The thing is, xpath is not cool for case insensitive comparison. If you have an <a> tag with href attribute that contains e.g. /Groups/ or /GROUPS/, it won't be matched. There is a workaround for this:
//a[contains(translate(#href, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '/groups/')]
As another option you could use LINQ with StringComparison.OrdinalIgnoreCase:
source.DocumentNode.Descendants("a")
.Where(a => a.GetAttributeValue("href", string.Empty)
.IndexOf("/groups/", StringComparison.OrdinalIgnoreCase) != -1
);
I could not find much examples of evaluate XPath using xerces-c 3.1.
Given the following sample XML input:
<abc>
<def>AAA BBB CCC</def>
</abc>
I need to retrieve the "AAA BBB CCC" string by the XPath "/abc/def/text()[0]".
The following code works:
XMLPlatformUtils::Initialize();
// create the DOM parser
XercesDOMParser *parser = new XercesDOMParser;
parser->setValidationScheme(XercesDOMParser::Val_Never);
parser->parse("test.xml");
// get the DOM representation
DOMDocument *doc = parser->getDocument();
// get the root element
DOMElement* root = doc->getDocumentElement();
// evaluate the xpath
DOMXPathResult* result=doc->evaluate(
XMLString::transcode("/abc/def"), // "/abc/def/text()[0]"
root,
NULL,
DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, //DOMXPathResult::ANY_UNORDERED_NODE_TYPE, //DOMXPathResult::STRING_TYPE,
NULL);
// look into the xpart evaluate result
result->snapshotItem(0);
std::cout<<StrX(result->getNodeValue()->getFirstChild()->getNodeValue())<<std::endl;;
XMLPlatformUtils::Terminate();
return 0;
But I really hate that:
result->getNodeValue()->getFirstChild()->getNodeValue()
Has it to be a node set instead of the exact node I want?
I tried other format of XPath such as "/abc/def/text()[0]", and "DOMXPathResult::STRING_TYPE". xerces always thrown exception.
What did I do wrong?
I don't code with Xerces C++ but it seems to implement the W3C DOM Level 3 so based on that I would suggest to select an element node with a path like /abc/def and then simply to access result->getNodeValue()->getTextContent() to get the contents of the element (e.g. AAA BBB CCC).
As far as I understand the DOM APIs, if you want a string value then you need to use a path like string(/abc/def) and then result->getStringValue() should do (if the evaluate method requests any type or STRING_TYPE as the result type).
Other approaches if you know you are only interested in the first node in document order you could evaluate /abc/def with FIRST_ORDERED_NODE_TYPE and then access result->getNodeValue()->getTextContent().