I am dealing with some auto-generated XSLT code.
It contains the following:
string(string(.))
number(string(.))
string(number(string(.)))
Is there any point to these? Or are they reducible to
string(.)
number(.)
string(.)
?
Like Martin says.
There are edge cases in XPath 2.0 where number(string(.)) is not exactly the same as number(.), for example if the context item is an instance of xs:gYear then number(.) will fail but number(string(.)) will succeed; contrariwise, if the context item is a boolean, number(.) will convert true to 1 and false to 0, while number(string(.)) converts both to NaN. But it's very unlikely that these edge cases are important to your application.
For the first one I am pretty sure it can be reduced to string(.). For the third one I don't think you can reduce it to string(.) as for instance for the context node having a character as its string content (e.g. <foo>a</foo>) doing number(string(.)) gives you the special number value "not a number" and if you do string() on that again you get (http://www.w3.org/TR/xpath/#section-Number-Functions, http://www.w3.org/TR/xpath/#section-String-Functions) the string "NaN". I am not sure about the second being reducible, maybe you can check the details of edge cases with the links I provided.
Related
In my env i am making two calls to get account details from different organization, and both organization return account details, but they are adding extra leading zeros in accountNumber, so my code is failing when i am comparing request and response account numbers, Is there any way to remove extra zeros from below xml using xslt.
<EAI>
<SvcRS>
<accountHeader>
<errorHost>orgA</errorHost>
</accountHeader>
<accoutnDetails>
<accountNumber>0000000111118800</accountNumber>
<accountType>credit</accountType>
<errorDetails>
<code>111</code>
<description>Account is not valid</description>
</errorDetails>
</accoutnDetails>
</SvcRS>
<SvcRS>
<accountHeader>
<errorHost>orgB</errorHost>
</accountHeader>
<accoutnDetails>
<accountNumber>000111118800</accountNumber>
<accountType>credit</accountType>
<errorDetails>
<code>0001</code>
<description>Not enough balance</description>
</errorDetails>
</accoutnDetails>
</SvcRS>
</EAI>
Thanks,
You can use format-number function as below:
<xsl:value-of select="format-number(.//accountNumber, '#')"/>
Result:
111118800
In XSLT 2 or later you can use replace(., '^0+', '') in the context of xsl:template match="accountNumber" to remove leading zeros with string operations (http://xsltfiddle.liberty-development.net/3Nqn5Y3/1) or you can use xs:integer(.) to remove the leading zeros by converting that value inside of element to an integer (http://xsltfiddle.liberty-development.net/3Nqn5Y3).
I am using tinyxpath-1.3.1. C/C++ on Linux. When I do a xpath search on a document I am not finding nodes when I think I should.
My XML:
<data>
<event deviceId="25479545.5" interface="sensor-multilevel"
command="state" label="luminance" newValue="800"
oldValue="9" time="1412227484" />
</data>
My xpath Expression:
/data/event[#deviceId="25479545.5" and #interface="sensor-multilevel" and
#label="luminance" and #newValue>600 and #oldValue<10]
If I take the oldValue out and use () like this the comparison works:
/data/event[(#deviceId="25479545.5" and #interface="sensor-multilevel") and
(#label="luminance" and #newValue>600)]
Is there some limit on the number of comparisons?
Anything special with converting the 600 to a decimal?
Do I need to "" the value 600, it seems to work either way.
Any ideas on how to get it to work with the oldValue attribute included in the expression?
TinyXPath call:
TiXmlNode * node = TinyXPath::XNp_xpath_node( root, expression.c_str() );
Thanks
Larry
You seem to be getting a string comparison here rather than a numeric comparison ("9" > "10" in alphabetic order). That's incorrect according to the specs (both XPath 1.0 and 2.0, though they get there in rather different ways).
The safest approach is probably to convert explicitly to a number: write
number(#oldValue) < 10
Looks like the tinyxpath library has some bugs....
This works for tinyxpath-1.3.1:
/data/event[((#deviceId="25479545.5" and #interface="sensor-multilevel") and
(#label="luminance" and #newValue>"600")) and (#oldValue<"10")]
parenthesis were needed to group these in a final set of 2.
Or I just convert to using libxml2.
I have 10 links in a list, upon clicked,which will open a new window. Different links would yield different set of pages, however i have 3 common elements for all 10 links.
Following is the function example.
def handle_window(self):
self.driver.go_to_new_window()
try: # block 1
elements = ["element1", "element2", "element3"]
for element in elements:
try: #block 2
self.assertEqual(True, is_exist_in_new_window(element)))
except:
continue
except:
# in 'try block 2' if assert yields true at least once,
print 'passed'
# if it fails for all 3 elements,
print 'failed'
self.driver.close_current_window()
self.driver.go_to_main_window()
I am not sure how do i evaluate the results of 'try block 2', so that to do some action in block 1.
Any possible solutions ?
If "element1", etc. are meant to be CSS selectors, the most efficient way would be:
elements = ["element1", "element2", "element3"]
self.assertTrue(exists_in_new_window(",".join(elements)))
(I've renamed is_exist_in_new_window to exists_in_new_window.) The , operator in CSS means "or". So the CSS selector passed to exists_in_new_window means you are looking for "element1" or "element2" or "element3". Doing it this way will need one round-trip between the Selenium client and the browser, no matter what. Note that the code above is not meant to handle meaningfully the case where elements is a zero-length list.
With XPath selectors you could use the | operator to perform a similar transformation. In this case, I would want to additionally use parentheses to preserve semantics of the individual selectors so something like "(" + ")|(".join(elements) + ")". (I believe the semantics issue does not arise in CSS due to CSS' very rigid syntax.)
In the more general case where it is not possible to combine the search criteria into one expression, one can fall back onto alecxe's suggestion:
elements = ["element1", "element2", "element3"]
self.assertTrue(any((exists_in_new_window(element) for element in elements)))
This method causes a minimum of min(1, len(elements)) round-trips between the Selenium client and the browser and a maximum of len(elements) depending on what is present on the page.
You can use any() to check if at least one element existed on a page:
elements = ["element1", "element2", "element3"]
value = any((is_exist_in_new_window(element) for element in elements))
self.assertTrue(value)
This code assumes is_exist_in_new_window() returns True or False.
Hope that helps.
Below is the xml. Now I am looking for an xslt where in the first loop of <ns0:EBLoop1> when EB01 = 1 then I need to get the value of <EB05>PACKAGE A STANDARD PLAN</EB05> in the next EBLoop1.
How can I do this.
<ns0:EBLoop1>
<ns0:EB>
<EB01>1</EB01>
<EB05>This</EB05>
<EB07>0</EB07>
</ns0:EB>
<ns0:MSG>
<MSG01>Please See the Provider Manual</MSG01>
</ns0:MSG>
</ns0:EBLoop1>
<ns0:EBLoop1>
<ns0:EB>
<EB01>D</EB01>
<EB05>PACKAGE A STANDARD PLAN</EB05>
<EB07>0</EB07>
</ns0:EB>
</ns0:EBLoop1>
<ns0:EBLoop1>
<ns0:EB>
<EB01>F</EB01>
<EB03>30</EB03>
<EB07>0</EB07>
</ns0:EB>
</ns0:EBLoop1>
Thanks,
Gopi
Assuming the context node is your EBLoop1 element, you can get the next one with xpath:
../following-sibling::ns:EBLoop1[1]/ns:EB/EB05
But you need to define your namespace and make use of the prefix in your xpath.
What I have is following:
<xsl:variable name="myvar" select=".//spss:category[((not #varName) or #varName=$colVarName) and #text=$series]/spss:cell/#text"/>
What it should do is select the text of the spss:cell's text-Attribute as long as it is a child of a spss:category that has
either a varName Attribute with a value equal to $colVarName
OR no varName Attribute at all
What is happening is following error message (sorry translating here, so just the gist of it):
Expected Token ')'. Found Token '#'.
.//spss:category[((not -->#<-- varName) or #varName=$colVarName...
Problem Solved! (See below)
OK, I think I found the mistake:
not must be used with parenthesis, so instead of
(not #varName) or #varName=$colVarName
it should have been
not(#varName) or #varName=$colVarName
indeed - not() is a function that returns the boolean opposite of whatever is between the parens. If necessary - it will cast its argument to a boolean. In this case, an empty node set casts automatically to false, so if #varName gives you an empty node set, not(#varName) will be true.