Page 1 of 1

Modify xinclude on insert

Posted: Tue Feb 16, 2016 9:50 pm
by steve.cuzner
I'm implementing a text entity replacement system using xinclude and need to modify the xinclude to the specific includes on insert. I've converted my entity file

Code: Select all

<!ENTITY foo '<b>foo</b>'>
<!ENTITY bar '<b>bar</b>'>
to

Code: Select all

<fileents>
<ent xml:id="foo"><b>foo</b></ent>
<ent xml:id="bar"><b>bar</b></ent>
</fileents
I then want to create an xinclude reference in another content file

Code: Select all

<para>Here is foo: <xi:include
href="file:/C:/fileents.xml"
xpointer="element(foo/1)"/>
</para>
(NOTE: we want to do this because we may use the same entity twice and if we only include the top element, we get duplicate ID errors, so by using the element() scheme and using a ChildSequence after the NCName we avoid the duplicates in the referencing file)

This works great. However, when using the Insert xinclude gui, when I select foo, it only puts foo in the xpointer field. So I need to intercept the insert to do a simple string substitution on insert. I expect I can modif the operationID field of action insert.xinclude from ro.sync.ecss.extensions.commons.operations.InsertXIncludeOperation to ro.sync.ecss.extensions.commons.operations.ExecuteMultipleActionsOperation and then add a new action to the serializableOrderMap to point to a new authorExtensionDescriptor/actionDescriptors that I'll define as ro.sync.ecss.extensions.commons.operations.XSLTOperation and write a simple xslt that will change the value of the xpoiter if the href matches fileents.xml.

Does this sound like a sound approach? Are there any pitfalls I should consider?

Re: Modify xinclude on insert

Posted: Wed Feb 17, 2016 12:54 pm
by alex_jitianu
Hi,

Yes, the solution you described is a sound approach. Unfortunately, the ro.sync.ecss.extensions.commons.operations.XSLTOperation wont work as you expected because in its XML source the xi:include is replaced with the actual referenced content (the default behavior from the XML parser). You can use one of the following operations instead:

1. in Oxygen v17.1 we added an operation that can execute an XQuery Update script directly over the author nodes model. If you are using this Oxygen version then you can use this operation: ro.sync.ecss.extensions.commons.operations.XQueryUpdateOperation. Don't forget to use true() as the activation XPath and the script looks like this:

Code: Select all

let $xp:= ancestor-or-self::*:include/@xpointer
return replace value of node $xp with concat('element(',$xp,'/1)')
2. Another operation you could use is ro.sync.ecss.extensions.commons.operations.JSOperation. This operation executes an Javascript and from this script you have access to our Java based API to manipulate the nodes model:

Code: Select all

function doOperation(){ 
//The current node is either entirely selected...
currentNode = authorAccess.getEditorAccess().getFullySelectedNode();
if(currentNode == null){
//or the cursor is placed in it
caretOffset = authorAccess.getEditorAccess().getCaretOffset();
currentNode = authorAccess.getDocumentController().getNodeAtOffset(caretOffset);
}
//Get current value of the @type attribute
currentValue = "";
currentValueAttr = currentNode.getAttribute("xpointer");
if(currentValueAttr != null){
currentValue = currentValueAttr.getValue();
}

//Create and set the new attribute value for the @type attribute.
attrValue = new Packages.ro.sync.ecss.extensions.api.node.AttrValue("element(" + currentValue + "/1)");
authorAccess.getDocumentController().setAttribute("xpointer", attrValue, currentNode);

}
Best regards,
Alex

Re: Modify xinclude on insert

Posted: Fri Feb 26, 2016 7:17 pm
by steve.cuzner
Hi,

This isn't working as expected. When I press the insert xinclude button now, the dialog never appears to select an item to include and then I end up with an xpointer on the parent tag of the insertion point:

Code: Select all

<para xpointer="element(/1)">This file contains ...</para>
I made all modifications using the Oxygen GUI and here are the output code in the framework file.

Here is the new action:

Code: Select all


									<poPatch>
<field name="fieldPath">
<String>authorExtensionDescriptor/actionDescriptors</String>
</field>
<field name="index">
<Integer>70</Integer>
</field>
<field name="value">
<action>
<field name="id">
<String>convert.xinclude.prodname</String>
</field>
<field name="name">
<String>Convert Product Name Xinclude</String>
</field>
<field name="description">
<String>Convert product name xinclude </String>
</field>
<field name="largeIconPath">
<String></String>
</field>
<field name="smallIconPath">
<String></String>
</field>
<field name="accessKey">
<String></String>
</field>
<field name="accelerator">
<null/>
</field>
<field name="actionModes">
<actionMode-array>
<actionMode>
<field name="xpathCondition">
<String>true()</String>
</field>
<field name="argValues">
<serializableOrderedMap>
<entry>
<String>script</String>
<String>function doOperation(){
//The current node is either entirely selected...
currentNode = authorAccess.getEditorAccess().getFullySelectedNode();
if(currentNode == null){
//or the cursor is placed in it
caretOffset = authorAccess.getEditorAccess().getCaretOffset();
currentNode = authorAccess.getDocumentController().getNodeAtOffset(caretOffset);
}
//Get current value of the @type attribute
currentValue = "";
currentValueAttr = currentNode.getAttribute("xpointer");
if(currentValueAttr != null){
currentValue = currentValueAttr.getValue();
}

//Create and set the new attribute value for the @type attribute.
attrValue = new Packages.ro.sync.ecss.extensions.api.node.AttrValue("element(" + currentValue + "/1)");
authorAccess.getDocumentController().setAttribute("xpointer", attrValue, currentNode);

}</String>
</entry>
</serializableOrderedMap>
</field>
<field name="operationID">
<String>ro.sync.ecss.extensions.commons.operations.JSOperation</String>
</field>
</actionMode>
</actionMode-array>
</field>
<field name="enabledInReadOnlyContext">
<Boolean>false</Boolean>
</field>
</action>
</field>
<field name="patchHandling">
<String>addIndex</String>
</field>
<field name="anchor">
<null/>
</field>
</poPatch>
And here is the patch for the insert.xinclude action:

Code: Select all


									<poPatch>
<field name="fieldPath">
<String>authorExtensionDescriptor/actionDescriptors/[32]/actionModes</String>
</field>
<field name="index">
<Integer>0</Integer>
</field>
<field name="value">
<actionMode>
<field name="xpathCondition">
<String>true()</String>
</field>
<field name="argValues">
<serializableOrderedMap>
<entry>
<String>actionIDs</String>
<String>ro.sync.ecss.extensions.commons.operations.InsertXIncludeOperation
convert.xinclude.prodname</String>
</entry>
</serializableOrderedMap>
</field>
<field name="operationID">
<String>ro.sync.ecss.extensions.commons.operations.ExecuteMultipleActionsOperation</String>
</field>
</actionMode>
</field>
<field name="patchHandling">
<String>addIndex</String>
</field>
<field name="anchor">
<null/>
</field>
</poPatch>

Re: Modify xinclude on insert

Posted: Fri Feb 26, 2016 8:47 pm
by steve.cuzner
Figured it out. I needed to keep insert.xinclude as in, created a new mw.insert.xinclude which calls the new custom action that does the multiple action call to insert.xinculde then the convert action.