Finding the node at the caret positoin

Post here questions and problems related to oXygen frameworks/document types.
Hydrogen
Posts: 15

Finding the node at the caret positoin

Thu Sep 18, 2014 3:06 pm

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?
Radu
Posts: 6055

Re: Finding the node at the caret positoin

Thu Sep 18, 2014 3:24 pm

Hi,

One question, do you want this when editing the XML in the Text or in the visual Author editing mode?

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Hydrogen
Posts: 15

Re: Finding the node at the caret positoin

Thu Sep 18, 2014 3:29 pm

The users are all using text mode.
Radu
Posts: 6055

Re: Finding the node at the caret positoin

Thu Sep 18, 2014 4:14 pm

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
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Hydrogen
Posts: 15

Re: Finding the node at the caret positoin

Thu Sep 18, 2014 5:08 pm

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:

Code: Select all

node()[oxy_caretposition()]
Radu
Posts: 6055

Re: Finding the node at the caret positoin

Fri Sep 19, 2014 2:09 pm

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
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
bk-one
Posts: 13

Re: Finding the node at the caret positoin

Thu Jan 10, 2019 7:27 pm

hi,
are there any developments regarding this?
thanks,
barbara
Radu
Posts: 6055

Re: Finding the node at the caret positoin

Fri Jan 11, 2019 1:02 pm

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
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com

Return to “SDK-API, Frameworks - Document Types”

Who is online

Users browsing this forum: No registered users and 1 guest