Page 1 of 1
Finding the node at the caret positoin
Posted: Thu Sep 18, 2014 3:06 pm
by Hydrogen
Hi,
In a plugin I need to extract data from at document relative to the current node, i.e. the node at which the caret is. First I need to find that node. I am using
evaluateXPath(). The problem is crafting the Xpath expression that will yield the correct node. I have found that the . operator will select the current element. If the caret is in a text node the . operator will select the enclosing element node.
node() and
text() will sometimes select way to much for my need. I will illustrate with this very simplified example:
Code: Select all
<xml>
<bigelement>
<element> textinside </element> textoutside
<element> textinside </element> textoutside
<element> textinside </element> textoutside
</bigelement>
<bigelement>
<element> textinside </element> textoutside
<element> textinside </element> textoutside with caret
<element> textinside </element> textoutside
</bigelement>
</xml>
If I place the caret at "textinside" both
node() and
text() will select the current text node and nothing else. If however I place the caret at "textoutside"
evaluateXPath() will return an array of nodes and I do not know how to pick the one with the caret in.
node() will select everything inside "bigelement", both element nodes and text nodes.
text() will select the four text nodes that are inside "bigelement" but not inside "element":
Code: Select all
/xml[1]/bigelement[2]/text()[1]
textoutside /xml[1]/bigelement[2]/text()[2]
textoutside with caret /xml[1]/bigelement[2]/text()[3]
textoutside /xml[1]/bigelement[2]/text()[4]
My question is: Can I craft an XPath expression that will return the text node with the caret in this case? If not, can I find (using Java code) which of the returned text nodes contain the caret?
Re: Finding the node at the caret positoin
Posted: Thu Sep 18, 2014 3:24 pm
by Radu
Hi,
One question, do you want this when editing the XML in the Text or in the visual Author editing mode?
Regards,
Radu
Re: Finding the node at the caret positoin
Posted: Thu Sep 18, 2014 3:29 pm
by Hydrogen
The users are all using text mode.
Re: Finding the node at the caret positoin
Posted: Thu Sep 18, 2014 4:14 pm
by Radu
Hi,
Unfortunately for the text page we do not have much API to help you navigate the nodes structure, we'll try to add more API for a future version.
My only suggestion would be something like this (I did not test the code below but with some small changes it should work):
Code: Select all
WSXMLTextNodeRange[] elementsByXPath = xmlTextPage.findElementsByXPath(".");
if(elementsByXPath != null && elementsByXPath.length > 0){
//This should always be only one match, the entire XML element inside which the caret is placed.
WSXMLTextNodeRange range = elementsByXPath[0];
int startOffset = xmlTextPage.getOffsetOfLineStart(range.getStartLine()) + range.getStartColumn() - 1;
int endOffsetOffset = xmlTextPage.getOffsetOfLineStart(range.getEndLine()) + range.getEndColumn() - 1;
int caretOffset = xmlTextPage.getCaretOffset();
//This should be a string containing all the XML element content (including start and end tags).
String xmlText = xmlTextPage.getDocument().getText(startOffset, endOffsetOffset - startOffset);
int offsetInXMLTextRelativeToStartRange = caretOffset - startOffset;
int lastEndTagOffset = xmlText.substring(0, offsetInXMLTextRelativeToStartRange).lastIndexOf(">");
int firstStartTagOffset = xmlText.indexOf("<", offsetInXMLTextRelativeToStartRange);
if(firstStartTagOffset != -1 && lastEndTagOffset != -1 && firstStartTagOffset < lastEndTagOffset){
//The text node containing the caret should be between them
String textNodeContent = xmlText.substring(lastEndTagOffset + 1, firstStartTagOffset);
}
}
Regards,
Radu
Re: Finding the node at the caret positoin
Posted: Thu Sep 18, 2014 5:08 pm
by Hydrogen
Thank you for the reply. I see that I will have to create some kind of workaround rather than believe I can craft a super XPath. That is actually helpful to know.
In the real application I am actually looking for data that is relative to the node with the caret. For example something like this:
Code: Select all
(node()/preceding::*/@href)[last()]
A possible workaround could be to use getCaretOffset() to compare to the output from findElementsByXPath() to select which of the outputs from evaluateXPath()to use. This assumes the two functions returnes the same number and sequence of nodes.
Another workaround might be to use regexp rather than XPath.
Thanks for your help!
Re possible future API I may have two immediate suggestions:
1) Implement
current() and let it represent the exact node at the caret (whatever node type that is). This will not break compatibility since
current() is not currently implemented. The difference between what is returned from the . operator and
current() may break peoples expectations.
2) Create an Oxygen proprietary function that returns the number of the caret containing node of a sequence. This would allow a construct like:
Re: Finding the node at the caret positoin
Posted: Fri Sep 19, 2014 2:09 pm
by Radu
Hi,
Please see some comments below:
A possible workaround could be to use getCaretOffset() to compare to the output from findElementsByXPath() to select which of the outputs from evaluateXPath()to use. This assumes the two functions returnes the same number and sequence of nodes.
Right, so call for example:
Code: Select all
WSXMLTextNodeRange[] ranges = access.findElementsByXPath("text()");
to get all the direct child text nodes of the current element in which the caret is, then use the text ranges to search for the range where the caret is placed. This could possibly work and be more elegant than my proposed workaround.
Another workaround might be to use regexp rather than XPath.
Yes, regexp is a possible fallback, using XML aware ways is always better if possible.
Re possible future API I may have two immediate suggestions:
1) Implement current() and let it represent the exact node at the caret (whatever node type that is). This will not break compatibility since current() is not currently implemented. The difference between what is returned from the . operator and current() may break peoples expectations.
2) Create an Oxygen proprietary function that returns the number of the caret containing node of a sequence. This would allow a construct like:
We'll take this into account, thanks for giving us feedback.
Regards,
Radu
Re: Finding the node at the caret positoin
Posted: Thu Jan 10, 2019 7:27 pm
by bk-one
hi,
are there any developments regarding this?
thanks,
barbara
Re: Finding the node at the caret positoin
Posted: Fri Jan 11, 2019 1:02 pm
by Radu
Hi Barbara,
So you are interested in API for the Text editing mode, right?
I did not find any mention that the proposals were implemented. But there is this method:
Code: Select all
ro.sync.exml.workspace.api.editor.page.text.xml.WSXMLTextEditorPage.getDocumentController()
https://www.oxygenxml.com/InstData/Edit ... oller.html
which allows you to insert XML fragments relative to a certain XPath expression which could be "." for example.
Regards,
Radu