Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing current() #73

Open
Hipska opened this issue Apr 13, 2022 · 32 comments
Open

Implementing current() #73

Hipska opened this issue Apr 13, 2022 · 32 comments

Comments

@Hipska
Copy link

Hipska commented Apr 13, 2022

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.

@Hipska
Copy link
Author

Hipska commented Apr 25, 2022

@zhengchun?

@zhengchun
Copy link
Contributor

current() is only supported by XSLT. You can try this //cd[@title=@ref]

@Hipska
Copy link
Author

Hipska commented Apr 27, 2022

Doesn't that only select cd nodes of which title attribute equals their ref attribute?

Edit: wow that actually worked.. Thanks man!

@Hipska Hipska closed this as completed Apr 27, 2022
@Hipska Hipska reopened this May 3, 2022
@Hipska
Copy link
Author

Hipska commented May 3, 2022

Scrap that, it seems it didn't work, it always picks the first one in this case: ../../measType[@p=@p] (as I would expect)

@zhengchun
Copy link
Contributor

Hello, Need a sample document to test.

or try this ../../measType[@p]

@Hipska
Copy link
Author

Hipska commented May 4, 2022

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.

@zhengchun
Copy link
Contributor

zhengchun commented May 4, 2022

like this //r[@p]/ancestor::measInfo/measType[@p]

//r[@p]/../../measType[@p]

@Hipska
Copy link
Author

Hipska commented May 4, 2022

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..

@zhengchun
Copy link
Contributor

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")+`']`){}
}

@Hipska
Copy link
Author

Hipska commented May 4, 2022

@zhengchun
Copy link
Contributor

zhengchun commented May 4, 2022

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.

@zhengchun zhengchun added the bug label May 4, 2022
@Hipska
Copy link
Author

Hipska commented May 5, 2022

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]?

@zhengchun
Copy link
Contributor

//r[@p=../../measType/@p] should be your expression to sove your problem.

@Hipska
Copy link
Author

Hipska commented May 5, 2022

No, I have an r and need an xpath to find it’s measType.

Your xpath selects every r that has a corresponding measType.

@Hipska
Copy link
Author

Hipska commented May 12, 2022

@zhengchun any update on this? Can I help to fix this?

@zhengchun
Copy link
Contributor

@Hipska , You can try to fix this and submit PR.

@Hipska
Copy link
Author

Hipska commented May 12, 2022

I would love to fix it, but I don't see where the bug is.

@zhengchun
Copy link
Contributor

Sorry,I no idea how to implement Current() now, It's a XSLT function.

@Hipska
Copy link
Author

Hipska commented May 21, 2022

Oh, but it seems you fixed it?

@zhengchun
Copy link
Contributor

I just fixed this expression a[@b=../@b], fixed bug with parent query on current node in the filter query.

@Hipska
Copy link
Author

Hipska commented May 23, 2022

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 👍

@Hipska
Copy link
Author

Hipska commented Jun 14, 2022

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?

@zhengchun
Copy link
Contributor

@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.

@Hipska
Copy link
Author

Hipska commented Aug 2, 2022

@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..

@zhengchun
Copy link
Contributor

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.

@Hipska
Copy link
Author

Hipska commented Feb 14, 2023

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.

@zhengchun
Copy link
Contributor

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]")

@Hipska
Copy link
Author

Hipska commented Feb 20, 2023

Yeah, the whole reason of this issue is because of the current() function is not implemented:

panic: not yet support this function current()

@Hipska
Copy link
Author

Hipska commented Jul 23, 2024

@zhengchun can you point me to where I could implement that?

@zhengchun
Copy link
Contributor

Implementing current() is a big work, you need to save the current matched node and then used by current() function. One possible approach is to use context package to save the current node.

@Hipska
Copy link
Author

Hipska commented Jul 25, 2024

Okay, but where could I start implementing it?

@zhengchun
Copy link
Contributor

  1. Add a new current() function:

    xpath/build.go

    Line 335 in 14e235f

    func (b *builder) processFunction(root *functionNode, props *builderProp) (query, error) {
  2. Save the current node in query interface, like child::*, descendant::*, parent::*...:

    xpath/query.go

    Line 53 in 14e235f

    type query interface {

These are only my guesses and cannot be guaranteed to be right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants