Page 1 of 1

Referencing list from another XML file

Posted: Wed Jan 08, 2014 3:32 am
by odaata
Hi all,

I'm trying to do something that I think should be fairly simple, but so far it hasn't been... I'd like to generate the items for a combobox using the values from another set of XML documents using my own private URI scheme. For example, for any field in the main XML that needs to have a person selected for it, I'd like to create a combobox with values from the person.xml file. Of course, this requires an XQuery or XSLT call to produce the results (I'm using XQuery because I'm more familiar with it and I find it to be easier to use). This could be (perhaps) the most basic use case for editing documents in Oxygen, but so far I don't see any easy or obvious way to do it. In the relational database world, this is THE use case for data - select a person from the Person table, the values being generated by a SQL statement. The CSS provided by Oxygen assumes all values are located in the document itself - but come on, how often is that really the case?

I've tried using a ReferenceResolver, but that assumes that I want to insert data from another file into the main one and it doesn't allow a user to select the record to be linked. I've looked at the LinkTextResolver, but again that just generates some text to be displayed by a link. I've recently decided to add a CSS combobox at runtime using a Styles Filter, but that class does not have access to AuthorAccess, so I can't get access to the EditorVariables (to resolve where the files are that my private URI scheme refers to) and the XMLUtilAccess class which has transformation functions.

Argh! This should be the easiest, simplest thing to do, and yet I can't see anywhere in the documentation where this use case is explicitly described except for the example using a custom Styles Filter. Any help would be greatly appreciated! If nothing else, can anyone tell me how to pass a reference to AuthorAccess to my custom Styles Filter from an Extensions bundle or even better, how I can access it from anywhere in my application? Is there a global value passed into the ExtensionsBundle at any point? So far I'm not seeing one...

Thanks in advance for any help you can provide!

Re: Referencing list from another XML file

Posted: Wed Jan 08, 2014 11:24 am
by alex_jitianu
Hello,

This is indeed a common use case for Oxygen and we have several ways to achieve your goal.

One of them is exactly the one you tried, namely by adding an combo box form control by using a StylesFilter. You are right, the documentation is a bit unclear about how to obtain the AuthorAccess instance. One way to do it is presented in the code snippet below:

Code: Select all


WSEditor editorAccess =
PluginWorkspaceProvider.getPluginWorkspace().getCurrentEditorAccess(PluginWorkspace.MAIN_EDITING_AREA);
if (editorAccess != null) {
WSEditorPage currentPage = editorAccess.getCurrentPage();
if (currentPage instanceof WSAuthorEditorPage) {
AuthorAccess authorAccess = ((WSAuthorEditorPage) currentPage).getAuthorAccess();
}
}
We already have recorded an issue to pass an AuthorAccess instance to the StylesFilter, so it will be available in one of the next versions.

Another approach which does not imply using Java is using the oxy_xpath() function (with XPath 2.0 features) to specify the values to be displayed in the oxy_combobox. For example, if you want to propose person names based on the data in another XML file (db.xml in our example) your CSS will look as below:

Code: Select all


combo {
content: "persons"
oxy_combobox(edit, '#text', values, oxy_xpath('string-join(doc("./db.xml")//person/@name, ",")'));
}
There is a third approach which has the advantage of offering these values in the content completion window and in the Attributes View besides the combobox form control. It uses the SchemaManagerFilter API interface which allows you to contribute values to the schema proposed content completion items. An example of using this API can be found in the user manual: http://oxygenxml.com/doc/ug-editor/#top ... ndler.html.

We have worked on a SchemaManagerFilter implementation that was able to read a configuration XML file (not yet released but fully functional). In this configuration file you could say that the values for an attribute or element should be obtained by executing an XSLT or XQuery. So all you have to do is write a configuration XML file and an XQuery script. If you are interested in it please let me know and I can send it to you to give it a try.

If you have further questions, please let me know.

Re: Referencing list from another XML file

Posted: Wed Jan 08, 2014 5:42 pm
by odaata
Thank you for your detailed reply! That does help immensely! The code snippet to get the AuthorAccess reference is very handy. I also didn't know there was another way of doing this using the SchemaManager - that sounds like a very nice option, since the values are embedded at a level "closer" to the data, so to speak. And I can still use the combobox via CSS to render those fields (with the list of values) since it's embedded in the Schema, so to speak, right? I would definitely like to give that a try. Can you send me the code/files for it and any documentation you have?

Thanks for your help!

Re: Referencing list from another XML file

Posted: Sat Jan 11, 2014 5:06 am
by odaata
OK, I've been playing around with the StylesFilter approach again, but I'm finding that the code snippet you gave me doesn't actually give me access to AuthorAccess when the styles load initially. When transitioning from Text to Author mode, the call to getCurrentPage() doesn't return the Author page, so I can't get AuthorAccess that way (reliably at least - it works when I debug the code and step through it!).

The main thing I need AuthorAccess for is to expandEditorVariables within the current framework and within the current project. So I tried the code below using the PluginWorkspace and WSEditor. This expands the project variable correctly for one path, but not the frameworks variable - perhaps because the editor isn't associated with a framework yet, since it's transitioning to Author mode? Keep in mind that this code is being called by my implementation of the StylesFilter Interface, so it fires as the Author view is loading.

Can you tell me how to do this? Or can I get access to these variables another way?

Here's the code I'm using:

Code: Select all


String sourceBase = EditorVariables.PROJECT_DIRECTORY + "/contextual_info/person.xml";
String xqueryBase = EditorVariables.FRAMEWORK_DIRECTORY + "/resources/contextual_info.xql";

PluginWorkspace ws = PluginWorkspaceProvider.getPluginWorkspace();
WSEditor access = ws.getCurrentEditorAccess(PluginWorkspace.MAIN_EDITING_AREA);

String sourceExpanded = ws.getUtilAccess().expandEditorVariables(
sourceBase, access.getEditorLocation()
);

String xqueryExpanded = ws.getUtilAccess().expandEditorVariables(
xqueryBase, access.getEditorLocation()
);

System.out.println(sourceExpanded);
// returns /home/user/Documents/Projects/emst/contextual_info/person.xml
System.out.println(xqueryExpanded);
// returns ${frameworkDir}/resources/contextual_info.xql
Thanks in advance for any help you can provide!

Re: Referencing list from another XML file

Posted: Mon Jan 13, 2014 12:35 pm
by alex_jitianu
Hi,

If you use PluginWorkspaceProvider.getPluginWorkspace().getUtilAccess() to get the UtilAccess the framework related editor variables are indeed not expanded. It's not an inherent limitation but just something we missed. Even more disturbing, the documentation states that these variables should be expanded no matter how you obtain the UtilAccess. I will add an issue to for the resolving to handle framework related variables no matter how the UtilAccess is obtained.

Until we fix the API I suggest to just ignore the StylesFilter.filter calls if the current page is not the AuthorPage. These calls come while the author document model is created and at this step we are only interested in the white-space properties. Afterwards, you will receives calls from the initial rendering and at that point the current page will be the AuthorPage.

Best regards,
Alex

Re: Referencing list from another XML file

Posted: Mon Jan 13, 2014 8:04 pm
by odaata
Well, I'm glad I could help you guys out a bit :-) I've taken your advice and only fire my code when AuthorAccess is available and it is working now.

Thanks so much for your help!

Re: Referencing list from another XML file

Posted: Wed Jan 29, 2014 4:58 pm
by Pascale
Additional question on the same subject: Is it possible to constraint the list of returned values from the external file to the content of the current document ? Preferably in CSS syntax...

My case:
I am reading values in an external XML file using oxy_xpath to populate a popup in the CSS file.
The following code is OK:

Code: Select all


family {
visibility: -oxy-collapse-text;
content: oxy_editor(
type, popupSelection,
edit, "#text",
values, oxy_xpath('string-join(doc("http://shared/config.xml")//family/name, ",")'),
selectionMode, "single",
columns, 40
);
}
However, I also need to filter values based on the content of the current document. Continuing my example, now that the user has selected a family, he should also select a product name and the popup should only contain the products related to the selected family.
In XSLT, I would use something like

Code: Select all


<xsl:variable name="thisFamily" select="../family" />
<xsl:value-of select="string-join(doc('http://shared/config.xml')//family[name=$thisFamily]/product, ',')" />
but I could not find a way to do it in CSS/oxy_xpath syntax.
I can obtain the list of names as a string when I use

Code: Select all


oxy_xpath(oxy_replace("doc('http://shared/config.xml')//family[name='$thisFamily']/product",'$thisFamily',oxy_xpath('../family/text()')))
Alas, when I try to apply the string-join() function to that expression, it does not work. I suspect that quotes should be escaped (how?)...
Can you help ?

Re: Referencing list from another XML file

Posted: Thu Jan 30, 2014 10:30 am
by alex_jitianu
Hi,

Using oxy_xpath and oxy_replace together should work just fine for your use case. If you try something like this do you get an error message?

Code: Select all


oxy_xpath(oxy_replace("string-join(doc('http://shared/config.xml')//family[name='$thisFamily']/product, ',')",'$thisFamily',oxy_xpath('../family/text()')))
I will send you a logger configuration file on the email to get more insight about the situation.

Best regards,
Alex

Re: Referencing list from another XML file

Posted: Thu Jan 30, 2014 3:09 pm
by Pascale
Hi Alex,

your solution works perfectly, thanks!
My problem was that I did not use the oxy_replace function at the right place: I was trying

Code: Select all

string-join(oxy_replace(...))
and that does not work !
Your solution

Code: Select all

oxy_replace("string-join(...))
is working.

Thanks also for the logger configuration instructions you sent me; I do not think I will need them for this specific case but will save the info for future usage.

However, could you give me more explanation about the use of the double and single quotes in an expression?
I understand that you should use single quotes inside a string delimited by double quotes, but I was expecting to have the closing double quote later in the expression, that is just before the closing ) of the oxy_replace function; or to need quotes around the doc() expression...

Best regards,
Pascale

Re: Referencing list from another XML file

Posted: Thu Jan 30, 2014 6:27 pm
by alex_jitianu
Hi,

First thing to keep in mind is that oxy_xpath and oxy_replace are CSS functions while string-join is an XPath one. We use oxy_replace as a helper to build the final XPath expression that will be given to an oxy_xpath to execute. Combining these two functions (oxy_xpath and oxy_replace) can be quite confusing sometimes... Here is the same example with some indentation to make it easier to read:

Code: Select all


oxy_xpath(
oxy_replace(
"string-join(doc('http://shared/config.xml')//family[name='$thisFamily']/product,',')",
"$thisFamily",
oxy_xpath("../family/text()")
)
)
Best regards,
Alex