xpath - get count of rows based on some text - xpath

I'm writing xpaths to select all the links under each category on left sidebar from following page:
http://www.indexmundi.com/commodities/'>http://www.indexmundi.com/commodities/
I want to select the link under each category one by one. I've written the following xpath and it is selecting the link under first category(Commodity Price Indices) somehow. But I was wondering how I will select the links under other categories. I want to add a check on h3 tha if it's text is Energy, count and select all the rows before that, then if h3 text is Beverages, count and select all rows between Energy and Beverages
.//*[#id='dlCommodities']/tbody/tr[position()< count(following-sibling::tr/td/h3)-1]/td/a
Here is another xpath:
.//*[#id='dlCommodities']/tbody/tr[preceding-sibling::tr/td/h3[. = 'Energy'] and following-sibling::tr/td/h3[. = 'Beverages']]/td/a
It is fulfilling the second requirement i.e. select rows between specific headings but it is missing one node.
Please help me fix these xpaths or suggest a better one.
Thanks

I understand your actual problem as: Find all links that belong to a given category. For doing so, find the category, and then retrieve all elements before the next category.
You might remove the newlines if you prefer, I added them for readability.
//tr[td/h3="Energy"]/(self::tr, following-sibling::tr[
. << //tr[td/h3="Energy"]/following-sibling::tr[td/h3][1]
])
If you do not have an XPath 2.0 compatible processor, you cannot use the << operator which test for node order (the current node must precede the next category). An XPath 1.0 solution is even slightly shorter, but in my opinion worse in readability:
//tr[td/h3="Energy"] | //tr[td/h3="Energy"]/following-sibling::tr[
./preceding-sibling::tr[td/h3][1][td/h3="Energy"] and not(td/h3)
]
Both queries will select all nodes of a category; to count them wrap them into count(...).

Related

how can I obtain a td with no value?

I have a table in which sometimes some records dont have a value
I am using these Xpath
//table/tbody/tr/td[not(td[string-length(normalize-space(text()))=0])]
//td[not(td[string-length(normalize-space(text()))=0])]
but it selects the whole table, how can I select only the td which are empty?
Thank you for all the help :)
Let's keep things simple. If you want to select tds without text try:
//table/tbody/tr/td[not(text())]
Demo
To complete, two alternatives to select empty td elements (the first one remove the useless parts of your XPath expression (normalize-space(), text(), and td[] inside the predicate) :
//td[string-length()=0]
//td[.=""]
The first XPath will look for td elements where the content length is equal to 0.
The second XPath will look for td elements which contain nothing.
But regarding your XPath tryouts, it seems you want to select td elements which are non-empty. If that's the case, just add a not inside the predicate :
//td[not(string-length()=0)]
//td[not(.="")]

spread out an item list by the quantity column in google sheets

How could I turn the left item list into right hand side list, and the ID column generate automatically will be great, thank you so much for solve my problem
I think this does what you want.
https://docs.google.com/spreadsheets/d/1V5UW20fqaAThCHX0inYrMt8AjQmflfZiCmk-G7HxAUM/edit?usp=sharing
Formula is:
=QUERY(ArrayFormula(FLATTEN(IFERROR(
SPLIT(
REPT(A2:A15 & "~", VLOOKUP(A2:A15,A2:B15,2,0)),
"~")
))),"select * where Col1 is not null",0)
The FLATTEN function, to flatten a range into one column, is apparently undocumented, but you can Google its use.
Let me know if this works for you.
Also, your input data was in alphabetical order. If this won't always be the case, the query could be modified, changing the last line to
"select * where Col1 is not null order by Col1".

XPath only get nodes from table when another node exists

I have a specific problem concerning XPath.
Say I can get a column from the table using this query:
//div[#id="someid"]/table/tbody/tr/td[9]/text()
However, I want to only get this column when another specific node exists.
I tried using:
//div[#id="someid"]/table/tbody/tr/td[9 and boolean(//a/span[#title='specifictitle'])]
This however does not work as it returns all items in the table.
I have a few specific limitations:
- //div[#id="someid"]/table/tbody/tr is static and cannot be changed.
- The td contains no other info concerning what column it is in.
Thanks in advance!
2 approaches:
First - as a direct condition within square brackets:
//div[#id="someid"]/table/tbody/tr[//a/span[#title='specifictitle']]/td[9]/text()
this approach is simpler and the position does not matter
this is also the approach that fulfills the OPs requirement, that the query should start with //div[#id="someid"]/table/tbody/tr
* You can basically put the condition [//a/span[#title='specifictitle']] to whatever element in the query you want (could also be behind tbody or table etc.)
Second - using axes (for example ancestor)
2 cases regarding the position of your element within HTML code:
1) anchor-element "before" your div with "someid":
//a/span[#title='specifictitle']//div[#id="someid"]/table/tbody/tr/td[9]/text()
2) anchor-element "after" your div with "someid":
//a/span[#title='specifictitle']/ancestor::div[#id="someid"]/table/tbody/tr/td[9]/text()
In both cases the xpath-query will not return a result if the //a/span[#title='specifictitle'] does not exist, which is what you needed, if I understood correctly

How to make Tableau run query for combined multiple selections in quick filter, example attached

It is hard to describe my question in the subject line. Here is an example.
I want Tableau to run query to show only Account ID that has both 2 products i selected in Product A quick filter.In this example only the second Account ID should qualify . Is this possible?
Thanks for your help in advance!
Hmm, good question. It is not possible in the way you want (at least I can't think of a way to do that), with quick filters.
I can solve your specific problem (filtering customers that have at least 2 specific products in their history), but expanding for variable n products can be really troublesome.
So first thing, create 2 parameters. Product1 and Product2. Each is a string, and you can get a list from the [Product A] field. You will use this 2 parameters to specify the 2 products you want.
Now create a calculated field, [Product flag]:
IF [Product A] = [Product1] OR [Product A] = [Product2]
THEN 1
END
Now drag [Account ID] to the filters shelf. Open the filter options and go to condition. Now select By field, [Product flag], Sum, = 2
That will work if there are not duplicated [Product A] under the same [Account ID]. If that can happen, you need a little bit more sophisticated approach. [Product Flag] becomes:
IF [Product A] = [Product1]
THEN 1
ELSEIF [Product A] = [Product2]
THEN 2
END
And the condition should be Count (Distinct) = 2
In both cases it will keep only the Account IDs that have both the products you selected under them. They can have other products under them.
EDIT: For the N product problem, I believe you're going to use a solution outside Tableau. One possibility is to use the JS API, so you can select the products you need in a JS interface, and pass a parameter to Tableau.
In JS you could have a list you could select as many items you want, and a script to pass a parameter to Tableau based on the selection. Could be something like: product1,product2,product3...
Then you could use CONTAINS() to see if that product is in that list (and raise a flag), and make a count of ',' to see how many products were selected.
Unfortunately I have very limited knowledge on JS API, but I strong encourage you to take a look
Really interesting question. It's surprisingly trickier to list the accounts that reference every product in a list than it is to list the accounts that reference any product in a list.
If you are willing to start with a less convenient user interface (suitable for ad-hoc analysis but not published dashboards) then try the following:
Create a filter based on Account Id, select Use all on the General tab, and By formula on the Condition tab. Enter the formula
Count(if [Product A] = "Business Office Consolidation" then 1 end) > 0 and Count(if [Product A] = "Cabled Barcode Scanner" then 1 end) > 0
This will only filter to only include Account IDs that reference both products. You can extend this to a list of any number of required products. For relational data sources, it is implemented using a HAVING clause.
Of course, it can be tedious to revise this formula by hand, but it is one way to accomplish your analysis goal, and it can be instructive to understand how filter conditions work. Similar formulas are useful for many conditions.
You can create one or more dynamic sets using the same approach and then use them in calculated fields, any shelf in Tableau and combine them to create new sets. You can also move the formula to a calculated field for convenience.
Note, the 1 in the formula is not significant, any non-null value would work. Since there is no else clause, the formula evaluates to null for rows that fail the if test. And the Count() function just counts the number of rows that have non-null values for the expression.
To come up with an approach that lets you easily select products from a list without editing a formula, will probably take some combination of more advanced features. I don't have an answer for you right now, but the features that are worth learning about that may or may not be part of the solution include filter actions, context filters, top filters, count distinct, custom SQL, computed sets, table calculations, LOD expressions and the Javascript API. This would also be a good questions to pose, with an example workbook, on the Tableau online forums at http://www.tableau.com under the Support menu.

XPATH select random number of nodes AND have multiple conditions

I need to select a random number of product details from XML and have multiple conditions.
The below selects 8 products, but they are not random - how to make this random?
$randomProducts = $prod_xml->xpath("/products/product[position()<
9]");
The below makes a selection on multiple conditions.
$featuredProducts = $prod_xml->xpath('/products/product[featured =1
and hidden !=1]');
How do I combine the two to get random featured products that are not set to hidden?
Depending on whether you want first to get all non-hidden and featured products an then select 8 of them, or get 8 products and then select all of them that are featured and non-hidden, you will have two different XPath expressions:
/products/product[featured =1 and hidden !=1][position() < 9]
and correspondingly:
/products/product[position() < 9][featured =1 and hidden !=1]
Now, the "random" part ...
Neither XPath 1.0 nor XPath 2.0 (or even the W3C working drafts for XPath 3.0 and its standard functions) have a function that returns a pseudo-random sequence of integers (or of anything).
Therefore, you have to form this sequence of eight pseudorandoms and generate an XPath expression as this:
/products/product[featured =1 and hidden !=1]
[contains('|3|5|12|19|4|23|11|7|', concat('|',position(),'|)) ]

Resources