Page 1 of 1

Automatically add specific optional elements

Posted: Thu Apr 30, 2015 9:24 am
by Patrik
Hi,

When I insert a new element oXygen will add all mandatory child elements as well, which is very nice. Now It occurs increasingly often that I add new elements to the xsd. To be downward compatible (i.e. not having to adapt all older documents), I don't want these new elements to be mandatory. But then the author has to insert them manually, which is quite unconfortable.

I'm aware of the possibilities to add a schematron rule (with quick-fix) or to implement an author action for inserting the parant element, but they both don't fit well.

Now I'd like to mark such optional elements as "insert it automativally when the parent element is inserted". This could look like this:

Code: Select all

<xs:element name="parent">
<xs:complexType>
<xs:sequence>
<xs:element name="optionalChild" minOccurs="0">
<xs:annotation>
<xs:appinfo>
<oxy:autoInsert/>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Is there already such a feature present or planned for the near future? (I remember it has been requested before). If not, could you give me some hints on how to add it to my custom extension bundle?

Thanks and regards,

Patrik

Re: Automatically add specific optional elements

Posted: Thu Apr 30, 2015 12:01 pm
by Radu
Hi Patrik,

Right now I am quite skeptical about adding an annotation in the XML Schema to suggest that an element should be inserted as if it were required although it is not.

Alex has a few days off so I'm not sure what previous discussions you had with him so sorry if I might repeat previous suggested solutions.

Have you tried using our ro.sync.contentcompletion.xml.SchemaManagerFilter API extension?

I tried to create an example for the DITA vocabulary, in DITA there is a section element which does not have title as a required element but most users might like the title to be inserted by default when a section is inserted via the content completion.

So I came up with this code:

Code: Select all

  /**
* Filter elements.
*
* @see ro.sync.contentcompletion.xml.SchemaManagerFilter#filterElements(java.util.List, ro.sync.contentcompletion.xml.WhatElementsCanGoHereContext)
*/
@Override
public List<CIElement> filterElements(List<CIElement> elements,
WhatElementsCanGoHereContext context) {
for (int i = 0; i < elements.size(); i++) {
CIElement elem = elements.get(i);
if("section".equals(elem.getName())){
CIElementAdapter titleElem = new CIElementAdapter(){
@Override
public String getQName() {
return "title";
}
@Override
public String getName() {
return "title";
}
};

//List of possible required children
List<CIElement> ges = elem.getGuessElements();
if(ges != null){
ges.add(0, titleElem);
} else {
elem.addGuessElement(titleElem);
}
}
}
return elements;
}

which adds "title" as a guess element (meaning a required child element) for the "section" element.
The code above seemed to work for me but I'm not sure if you would consider it useful for your situation.

Regards,
Radu

Re: Automatically add specific optional elements

Posted: Thu Apr 30, 2015 3:48 pm
by Patrik
Hi Radu,

I had no previous discussions about this yet. But I already had a customized SchemaManagerFilter - not for adding guessElement, though.

With your code I could make it work adding a specific optional element. Thanks for that. :)

However, I'm still looking for a comfortable way to mark the "recommended" elements (non-mandatory but still automatically inserted). One way would we an additional configuration file that is ready by my framework on startup. But I still like the idea to do it directly within the xsd. Do you have another idea how this could be done? And is there actually a way to access additional schema data (i.e. a list pf possibe child elements with the type information) from within the filterElements method when I have only an instance of CIElement?

Thanks and regards,
Patrik

Re: Automatically add specific optional elements

Posted: Thu Apr 30, 2015 4:51 pm
by Radu
Hi Patrik,

Right now the CIElement does not allow accessing additional annotations which were set in the schema for it.
If you were to do this on your side you could either:

1) Keep annotations in the schema and possibly apply an XSLT stylesheet which produces a more simple XML file which can be loaded by the schema manager filter.

2) Load the schema using Xerces structures directly from the schema manager filter and look for those annotations.

3) Or you could mark the element as required in the schema and update all existing XML documents to contain it. Oxygen 17 will have an XML Refactor feature which can be used to batch process XML files and modify them.

If we were to improve this on our side:

1) Either we can support your original idea of using a specific annotation from the schema to consider an element as required for the content completion although not specified as required in the schema

2) Or somehow provide on the CIElement a way to access the original annotations which were assigned to it in the schema.

I will add an issue on our side for this. I'm not sure it is something which would benefit others that much though.

Regards,
Radu

Re: Automatically add specific optional elements

Posted: Mon May 04, 2015 9:27 am
by Patrik
Hi Radu,

Thanks for your thoughts. I'm using an xml file as configuration now and it works fine.

If it turns out to be usefull I will follow your suggestion and replace this xml file by the result of an xsl transformation from the xml schema.

So for me there's no need for any improvement from your side.


But one (small) problem resides: I'm using the same extension bundle for different document types. Now I'd like to have a different configuration file for each document type: My idea is to use a fixed path relative to the framework directory (like "config/AutoCompletionConfig.xml"). How can I identify the url of the current framework directory from within my instance of ExtensionBundle?

Thanks and regards,
Patrik

Re: Automatically add specific optional elements

Posted: Mon May 04, 2015 10:43 am
by Radu
Hi Patrik,

Here's how I would do this:

Each document type customization has a "Classpath" list containing a list of folders and JAR libraries which will be added to the Java class loader which will load the extensions bundle.
Each of your document type customizations could have in the Classpath list an additional identical entry like:

${framework}/config/

The config folder would reside in each framework folder and would contain the specific "AutoCompletionConfig.xml" file.

Then in the schema manager filter Java implementation class you can use code like:

getClass().getClassLoader().getResource("AutoCompletionConfig.xml")

to get an URL which points to a resource called "AutoCompletionConfig.xml" in the current classpath. The resource will get mapped to the resource from the config folder loaded in the current specific framework.

Another possibility:
The schema manager filter is created on the callback ExtensionsBundle.createSchemaManagerFilter(). You could pass on its constructor the name of the document type by calling getDocumentTypeName() on the extensions bundle instance. This could allow you to differentiate in the filter if it was created in one document type or in the other.
For example you could use the API:

Code: Select all

PluginWorkspaceProvider.getPluginWorkspace().getUtilAccess().expandEditorVariables("${frameworkDir(" + documentTypeName + ")} ", null);
to find the framework directory based on the document type name.

Regards,
Radu

Re: Automatically add specific optional elements

Posted: Mon May 04, 2015 11:24 am
by Patrik
Hi Radu,

your suggested solution with the classpath works fine and feels good. Thanks again.

Patrik

Re: Automatically add specific optional elements

Posted: Mon May 04, 2015 1:02 pm
by Patrik
Hi again,

I just noticed that there is another problem when using this in author mode: the additional guess element is not rendered correctly until a refresh. In your original example with the title element in section this means that the text you enter is not being bold (In my use-cases the difference is much more obvious). It appears to be rendered like an element without any css rules matching it!?

I tried to add the default value for the class attribute but it seemed to have no effect:

Code: Select all

@Override
public List<CIElement> filterElements(List<CIElement> elements, WhatElementsCanGoHereContext context) {
for (CIElement elem: elements) {
if("section".equals(elem.getName())){
CIElementAdapter titleElem = new CIElementAdapter(){
@Override
public String getQName() {
return "title";
}
@Override
public String getName() {
return "title";
}
};

// default attributes
List<CIAttribute> attrList = new LinkedList<CIAttribute>();
attrList.add(new CIAttribute("class", false, false, "- topic/title", null));
titleElem.setAttributes(attrList);

//List of possible required children
List<CIElement> ges = elem.getGuessElements();
if(ges != null){
ges.add(0, titleElem);
} else {
elem.addGuessElement(titleElem);
}
}
}
return elements;
}
What is missing here?

Patrik

Re: Automatically add specific optional elements

Posted: Mon May 04, 2015 3:25 pm
by Radu
Hi Patrik,

Your intuition is true, you also need to set the default attribute with name and value.
The created element is an adapter so using setAttributes on it does nothing.
But you can do something like:

Code: Select all

          CIElementAdapter titleElem = new CIElementAdapter(){
@Override
public String getQName() {
return "title";
}
@Override
public String getName() {
return "title";
}
@Override
public List<CIAttribute> getAttributes() {
return Arrays.asList(new CIAttribute("class", false, false, "- topic/title", null));
}
};
Regards,
Radu

Re: Automatically add specific optional elements

Posted: Tue May 05, 2015 7:39 am
by Patrik
Hi Radu,

overriding the set/getAttributes methods in my already existing class BasicCIElement indeed solved that problem.

Thanks
Patrik

Re: Automatically add specific optional elements

Posted: Fri Aug 26, 2016 3:22 pm
by mu258770
Hi Radu/Alex,

I have done the below coding in my oXygen maven setup for inserting <p> automatically when <note> is inserted. But it does not work. Could you please let me know what I am missing here. Do I need to add the extension in plugin.xml?

Code: Select all

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import ro.sync.contentcompletion.xml.CIAttribute;
import ro.sync.contentcompletion.xml.CIElement;
import ro.sync.contentcompletion.xml.CIElementAdapter;
import ro.sync.contentcompletion.xml.CIValue;
import ro.sync.contentcompletion.xml.Context;
import ro.sync.contentcompletion.xml.SchemaManagerFilter;
import ro.sync.contentcompletion.xml.WhatAttributesCanGoHereContext;
import ro.sync.contentcompletion.xml.WhatElementsCanGoHereContext;
import ro.sync.contentcompletion.xml.WhatPossibleValuesHasAttributeContext;

public class SDFSchemaManagerFilter implements SchemaManagerFilter {


@Override
public List<CIValue> filterElementValues(List<CIValue> arg0, Context arg1) {
// TODO Auto-generated method stub
return null;
}

@Override
public List<CIElement> filterElements(List<CIElement> elements, WhatElementsCanGoHereContext context) {
// TODO Auto-generated method stub

for (CIElement elem: elements) {
if("note".equals(elem.getName())){
CIElementAdapter titleElem = new CIElementAdapter(){
@Override
public String getQName() {
return "p";
}
@Override
public String getName() {
return "p";
}
@Override
public List<CIAttribute> getAttributes() {
return Arrays.asList(new CIAttribute("class", false, false, "- topic/p", null));
}
};

// default attributes
List<CIAttribute> attrList = new LinkedList<CIAttribute>();
attrList.add(new CIAttribute("class", false, false, "- topic/p", null));
titleElem.setAttributes(attrList);

//List of possible required children
List<CIElement> ges = elem.getGuessElements();
if(ges != null){
ges.add(0, titleElem);
} else {
elem.addGuessElement(titleElem);
}
}
}
return elements;

}

@Override
public String getDescription() {
// TODO Auto-generated method stub
return null;
}

@Override
public List<CIValue> filterAttributeValues(List<CIValue> arg0,
WhatPossibleValuesHasAttributeContext arg1) {
// TODO Auto-generated method stub
return null;
}

@Override
public List<CIAttribute> filterAttributes(List<CIAttribute> arg0,
WhatAttributesCanGoHereContext arg1) {
// TODO Auto-generated method stub
return null;
}


}
Also we are moving to oXygen 18.0. Is there any support for these auto-insertion of elements by just some configuration changes?

Regards,
Shabeer

Re: Automatically add specific optional elements

Posted: Fri Aug 26, 2016 4:15 pm
by Radu
Hi Shabeer,

So how exactly are you using the custom SDFSchemaManagerFilter?
Have you added logging on the "filterElements" method, is it called by Oxygen?
As a much easier workaround, starting with Oxygen 18.0 there is a content completion configuration XML file which can be used to force insertion of a subelement when a parent element is inserted:

https://www.oxygenxml.com/doc/versions/ ... ually.html

Regards,
Radu

Re: Automatically add specific optional elements

Posted: Fri Jan 20, 2017 1:42 pm
by mu258770
Hi team,

Regarding the possibility of the configuration changes in oXygen 18, we would like to have an attribute and its value to be inserted for a particular element by default when it is inserted.

For eg:- If we would like to have print="yes" for <glossref> by default, what to be added in the config file. We want it to be added once <glossref> is inserted.

<elementProposals path="glossref" insertAttributes="print"/>

By using this , it makes <glossref print="no"> when we insert the <glossref> in oXygen (this is because the default value for print="no" for <glossref>). But we need to change the value to be "yes" by default. What can we do in this case?

Thank you!

Regards,
Shabeer

Re: Automatically add specific optional elements

Posted: Mon Jan 23, 2017 5:26 pm
by Radu
Hi Shabeer,

Unfortunately you cannot state in the "cc_config.xml" that a certain inserted attribute should be inserted with a certain value.
If your end users edit the XML only in the Author visual editing mode, you can edit the document type association configuration for it and create a custom Author action which inserts the XML element with the proper content. Then in the Author->Content Completion tab you can remove from the content completion list the initial element name and add to the list your custom action with the same name as the original element name.
So when end users will use the content completion list to insert that element, they will actually call your custom Author action.

Regards,
Radu

Re: Automatically add specific optional elements

Posted: Tue Feb 21, 2017 10:53 am
by mu258770
Hi,

For keeping auto-insertion of <p> inside <entry> element, we have added below line of code to cc_config.xml,

Code: Select all

<elementProposals path="row/entry" insertElements="p"/>
But that does not work when we insert <table> using "table wizard" option from content completion. In other contexts wherever we have used the technique, it worked. We assume that the issue could be because <entry> is added by default when <table> is inserted through wizard.

Could you please let us know whether there is any other way we could achieve <p> auto-insertion in <entry> using configs.

Thank you!

Regards,
Shabeer

Re: Automatically add specific optional elements

Posted: Tue Feb 21, 2017 3:25 pm
by Costin
Hi,

Thank you for the feedback!
We will investigate this behavior and its cause.
It seems that setting

Code: Select all

<elementProposals path="row/entry" insertElements="p"/>
in the cc_config.xml actually works, but only when editing in Text mode.
As a workaround for Author editing mode, you could pass the "<p/>" element as a value for the "Insert table" Author mode action.

To do this, go into the menu Options > Preferences > Document Type Associations and edit your "DITA" framework.
In the "Actions" section of the "Author" tab, you should edit the "insert.table" action and set "<p></p>" as value for the "cellFragment" operation, then click "OK" in all open dialogs.

This way, whenever you use the "Insert table" action in Author mode, either from the context menu or through the corresponding toolbar action, each of your table's "entry" elements will have a paragraph as its child.

I hope this helps!

Regards,
Costin

Re: Automatically add specific optional elements

Posted: Thu Feb 23, 2017 8:32 am
by mu258770
Hi Costin,

Thank you for your response!

The solution works well for <entry> :)

We still have one more query though regarding the auto-insertion of elements.

Consider we have added the configuration change for auto-insertion of <p> for <note> element doing the below additional coding in the config file cc_config.xml,

Code: Select all

<elementProposals path="note" insertElements="p"/>
This works in a way that when <note> element is inserted, directly an inner <p> element gets inserted.
Instead of creating the <p> element right away when <note> is inserted, we would even prefer a solution where the <p> element is created when you start to type inside the parent element (here its <note>). Could we also do that configuration for some elements where we require?

We have seen it works well for <cmd> in <step>. If we remove <cmd> element from <step> and starts typing, the <cmd> gets auto-inserted and content gets inside the <cmd>. This behavior is more user friendly and we would like this to be achieved for some other elements in our list.

Please let us know if there is any way we could achieve this behaviour.

Thank you!

Regards,
Shabeer

Re: Automatically add specific optional elements

Posted: Thu Feb 23, 2017 1:43 pm
by Costin
Hi Shabeer,

The "cc_config.xml" file serves only as a configuration layer used for the purpose of adding or removing elements and attributes to be proposed by the Content Completion.

However defining rules to control dynamical content completion proposals can not be done through the same means.
Instead this can be achieved programmatically through the Author extensions API, by overriding methods from the AuthorDocumentFilter class.
The AuthorDocumentFilter class is used to filter the AuthorDocumentController methods responsible for modifying the Author document.

Fore more details you could consult the AuthorDocumentFilter API Javadoc and take a look at the usage example, both available HERE

Modifying the class in order to obtain specific results implies strong Java programming background.

Regards,
Costin