xpath
xpath copied to clipboard
Implementing `current()`
I'm wondering why the current()
function hasn't been implemented, and if it would make much time to do so.
I'm currently in the situation where I would need a query like //cd[@title=current()/@ref]
. The node navigator used for the expression evaluate isn't the document root, but a previously selected node.
@zhengchun?
current()
is only supported by XSLT. You can try this //cd[@title=@ref]
Doesn't that only select cd
nodes of which title attribute equals their ref attribute?
Edit: wow that actually worked.. Thanks man!
Scrap that, it seems it didn't work, it always picks the first one in this case: ../../measType[@p=@p]
(as I would expect)
Hello, Need a sample document to test.
or try this ../../measType[@p]
That gives the same result. Its strange, as I was really under the impression your solution first worked..
Anyway, this is a simplified version of the file:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="MeasDataCollection.xsl"?>
<measCollecFile xmlns="http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec">
<measData>
<managedElement localDn="foobar.example.com" />
<measInfo measInfoId="metric_name">
<measType p="1">field1</measType>
<measType p="2">field2</measType>
<measValue measObjLdn="identifier">
<r p="1">31854</r>
<r p="2">159773</r>
</measValue>
</measInfo>
<measInfo measInfoId="metric_name2">
<measType p="1">field3</measType>
<measType p="2">field4</measType>
<measValue measObjLdn="identifier">
<r p="1">1234</r>
<r p="2">567</r>
</measValue>
</measInfo>
</measData>
</measCollecFile>
And the selected node is each time r
, so I need an xpath to find out the field name of it.
like this //r[@p]/ancestor::measInfo/measType[@p]
//r[@p]/../../measType[@p]
That's even worse, now all metrics have field name field1
.
The Path is run on each r
node. So I think only ../../measType[@p=current()/@p]
would work..
using the nested query to solve. like this
for _,n:=range xmlquery.Find(doc,"//r[@p]")
{
for _,nn:=range xmlquery.Find(n,`../../measType[@p='`+n.SelectAttr("p")+`']`){}
}
Well, yeah. I can't change the code. I'm using telegraf: https://github.com/influxdata/telegraf/blob/6dc2b99549b3fc4684295ebcd2975cee96a1fa28/plugins/parsers/xpath/parser.go#L419-L447
I tested //r[@p=../../measType/@p]
and it only return the first one node(expected matched 4 node but only gave 2), this is a bug.
Indeed, see GO playground vs XPather. Can I help with trying to fix it?
Edit: And what should be the correct path be after the fix? ../../measType[@p]
or ../../measType[@p=@p]
?
//r[@p=../../measType/@p]
should be your expression to sove your problem.
No, I have an r
and need an xpath to find itβs measType.
Your xpath selects every r that has a corresponding measType.
@zhengchun any update on this? Can I help to fix this?
@Hipska , You can try to fix this and submit PR.
I would love to fix it, but I don't see where the bug is.
Sorry,I no idea how to implement Current()
now, It's a XSLT function.
Oh, but it seems you fixed it?
I just fixed this expression a[@b=../@b]
, fixed bug with parent query on current node in the filter query.
Hmm, then this playground should return 4 nodes, right? https://go.dev/play/p/qeMkl0NqoOT
Edit: nevermind, there is no release yet π https://go.dev/play/p/sI48ALhbizY π
I just tested latest version of telegraf (which includes the latest version of this library), but my use-case seems still not to be solved. I'm also not sure what the correct xpath for my problem should be.
Edit: See the following https://go.dev/play/p/ozvF3CfdDXT I would expect this to be the output of that:
#0 <r p="1">31854</r>
<measType p="1">field1</measType>
#1 <r p="2">159773</r>
<measType p="2">field2</measType>
#2 <r p="1">1234</r>
<measType p="1">field3</measType>
#3 <r p="2">567</r>
<measType p="2">field4</measType>
Program exited.
Do You agree? If not, what should my second xpath query be to achieve this wanted result?
@Hipska , The actually result from your go code execute is correct, your expect result is not right.
for i, n := range xmlquery.Find(doc, "//r[@p=../../measType/@p]") {
fmt.Printf("#%d %s\n", i, n.OutputXML(true))
for _, nn := range xmlquery.Find(n, `../../measType[@p=./@p]`) { -- Here
fmt.Printf("\t%s\n", nn.OutputXML(true))
}
}
xmlquery.Find(n, ../../measType[@p=./@p]
), HERE, you tell xpath to start search from the specified node n
, xpath will according on your ../../measType[@p=./@p]
to matching. and @p=./@p
just telling xpath target node have @p
attribute, not your expect `@p=n[@p]'.
You should change your query from xmlquery.Find(n, "../../measType[@p=./@p]")
to xmlquery.Find(n, "../../measType[@p=β+ n.Attr("p") +β]β)
You can try take your xpath expression execute on the another program language and see the result.
@zhengchun sorry for this late response. the code itself cannot be changed as this is what telegraf is doing. So I am looking for the correct xpath query to achieve my wanted result..
So, what is your expected xpath if we can implement the current()
function.
In the above example, if you can nested for...loop
why you can't change xpath expression to replace ../../measType[@p=./@p]
with ../../measType[@p=β+ n.Attr("p") +β]
?
You can provide an example and what is you expected result.
Hi, sorry to be so late on this..
In the telegraf config, I'm only able to pass a string, see earlier shared code. So I need a single string/xpath that returns the expected measType
node. ../../measType[@p=β+ n.Attr("p") +β]
is not possible and will not work.
I find a solution that saving the query node 'n' as a local variable used
by current()
function in the query context, like this jsonquery.Find(n,"../../measType[@p=current()/@p]")
Yeah, the whole reason of this issue is because of the current()
function is not implemented:
panic: not yet support this function current()