Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post here questions and problems related to oXygen frameworks/document types.
Johann
Posts: 198
Joined: Wed Jun 17, 2015 12:46 pm

Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Johann »

Hi everyone,

In the Author Component, I try to test
Configuring Proposed Values in the Context that the Content Completion was Invoked
from https://www.oxygenxml.com/doc/versions/ ... -proposals

An EE or PE version of SAXON is required to perform this configuration.

Is there a way to use another XSLT Processor in the Author Component instead of SAXON ?

Thank your for your response,

Johann
alex_jitianu
Posts: 1007
Joined: Wed Nov 16, 2005 11:11 am

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by alex_jitianu »

Hi Johann,

In theory the XSLT should run just fine with Saxon-HE (which is available in the Author Component) as long as the XSLT doesn't use any functionality available only in the PE/EE versions. If you would need access to the element for which the CC was invoked, you will run into this issue (because saxon:eval() is not available in the HE version).

Code: Select all

        <xsl:variable name="propertyElement" 
select="saxon:eval(saxon:expression($contextElementXPathExpression, ./*))"/>
Unfortunately there is no workaround for this other than using the Java API instead and implementing a SchemaManagerFilter.

Best regards,
Alex
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello Everyone,

I try to implement this solution in our ContentCompletionConfigurator java class with Saxon PE.
But when I execute this :

Code: Select all

ProfessionalTransformerFactory fac = new ProfessionalTransformerFactory();
I get this error :

Code: Select all

java.lang.SecurityException: class "net.sf.saxon.Configuration$ApiProvider"'s signer information does not match signer information of other classes in the same package
   at java.lang.ClassLoader.checkCerts(ClassLoader.java:898) ~[na:1.8.0_112]
   at java.lang.ClassLoader.preDefineClass(ClassLoader.java:668) ~[na:1.8.0_112]
   at java.lang.ClassLoader.defineClass(ClassLoader.java:761) ~[na:1.8.0_112]
   at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_112]
   at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_112]
   at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[na:1.8.0_112]
   at java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_112]
   at java.net.URLClassLoader$1.run(URLClassLoader.java:362) ~[na:1.8.0_112]
   at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_112]
   at java.net.URLClassLoader.findClass(URLClassLoader.java:361) ~[na:1.8.0_112]
   at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_112]
   at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_112]
   at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_112]
   at com._4dconcept.adam.author.plugin.contentCompletion.ContentCompletionConfigurator.updateCCConfigurationFile(ContentCompletionConfigurator.java:84) ~[classes/:na]
   at com._4dconcept.adam.author.plugin.views.S1000DDownloaderOpenerWorker.doBeforeWork(S1000DDownloaderOpenerWorker.java:30) ~[classes/:na]
   at com._4dconcept.adam.author.plugin.views.AbstractDownloaderOpenerWorker.doInBackground(AbstractDownloaderOpenerWorker.java:66) ~[classes/:na]
   at javax.swing.SwingWorker$1.call(SwingWorker.java:295) [na:1.8.0_112]
   at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_112]
   at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_112]
   at javax.swing.SwingWorker.run(SwingWorker.java:334) [na:1.8.0_112]
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_112]
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_112]
   at java.lang.Thread.run(Thread.java:745) [na:1.8.0_112]
It seems that it does not take the good net.sf.saxon.Configuration class.

I have checked with mvn dependency:tree, and I am sure only Saxon PE is called.
Would there be a conflict with oxygen jars?
Have you ever encountered this mistake ?
If yes, how did you solve it ?

Thanks for any help.
Regards,
Isabelle
Radu
Posts: 8991
Joined: Fri Jul 09, 2004 5:18 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Radu »

Hi Isabelle,

The Author Component SDK also comes with a Saxon HE JAR library called something like "oxygen-patched-saxon-9". So adding an extra Saxon 9 library directly to the classpath will not work.
You can either use our API to create a Saxon HE transformer:

Code: Select all

PluginWorkspaceProvider.getPluginWorkspace().getXMLUtilAccess().createXSLTTransformer(styleSource, new URL[0], XMLUtilAccess.TRANSFORMER_SAXON_HOME_EDITION)
or if you have a commercial license for Saxon PE and you explicitly want to use Saxon PE with our component you will probably need to load the Saxon PE libraries on a separate Java class loader using Java reflection so that they do not interfere with ours.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello Radu,

As Alex said, we can not use Saxon HE to implement your solution because saxon:eval() is not available in the HE version.
It is not possible to "exclude" oxygen-patched-saxon-9 with Maven ?

Regards,
Isabelle
Radu
Posts: 8991
Joined: Fri Jul 09, 2004 5:18 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Radu »

Hi Isabelle,

Our code absolutely needs the "oxygen-patched-saxon-9" in its current form, otherwise it might break in unexpected places.
Two possible workarounds for you:

1) XSLT 3.0 added the xsl element xsl:evaluate:

https://stackoverflow.com/questions/472 ... te-example

and using it should work even with Saxon HE.

2) Do not add your Saxon JAR library to the Maven class path, place it (and its commercial license) in another folder, create from the code an URLClassLoader which loads the JAR library and then license folder, then use that class loader to load the classes you are interested in and work with them using Java reflection.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hi Radu,

I tried to create from the code an URLClassLoader which loads the JAR library, and then use that class loader to load classes I need and work with them using Java reflection.

Here is my code

Code: Select all

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SaxonPEUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(SaxonPEUtils.class);
    private static final String SAXON_PE_PATH = "C:/apps/saxon-pe/saxon9pe.jar";

    public static Object newSaxonPETransformer(Source xslt) {
        Object transformer = null;

        try {
            File externalJar = new File(SAXON_PE_PATH);
            if(externalJar.exists()) {
                URLClassLoader saxonClassLoader = new URLClassLoader(new URL[]{externalJar.toURI().toURL()}, ClassLoader.getSystemClassLoader());
                Class<?> classToLoad = saxonClassLoader.loadClass("com.saxonica.config.ProfessionalTransformerFactory");
                Constructor<?> conTest = classToLoad.getConstructor();
                Object proTransformerFactory = conTest.newInstance();
                Method method = proTransformerFactory.getClass().getMethod("newTransformer", Source.class);
                transformer = method.invoke(proTransformerFactory, xslt);
            } else {
                System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
                transformer = TransformerFactory.newInstance().newTransformer();
                LOGGER.error("Saxon PE not found in " + externalJar.getAbsolutePath() + ". Saxon HE TransformerFactory.newTransformer() provided instead.");
            }
        } catch (ClassNotFoundException | IllegalAccessException |InvocationTargetException | InstantiationException | NoSuchMethodException | MalformedURLException | TransformerException e) {
            LOGGER.error(e.getMessage(), e);
        }

        return transformer;
    }
}
Even if I specify an external class loader as parent ClassLoader.getSystemClassLoader(), it does not work because it still looking in oxygen-patched-saxon-9he-21.1.0.2.jar.
[SwingWorker-pool-8-thread-2] ERROR c._.a.a.plugin.utils.SaxonPEUtils - SYSTEM - null
java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_112]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_112]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_112]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_112]
at plugin.utils.SaxonPEUtils.newSaxonPETransformer(SaxonPEUtils.java:30) ~[classes/:na]
at plugin.contentCompletion.ContentCompletionConfigurator.updateCCConfigurationFile(ContentCompletionConfigurator.java:75) [classes/:na]
at plugin.views.OpenerWorker.doBeforeWork(OpenerWorker.java:30) [classes/:na]
at plugin.views.AbstractOpenerWorker.doInBackground(AbstractOpenerWorker.java:66) [classes/:na]
at javax.swing.SwingWorker$1.call(SwingWorker.java:295) [na:1.8.0_112]
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_112]
at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_112]
at javax.swing.SwingWorker.run(SwingWorker.java:334) [na:1.8.0_112]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_112]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_112]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_112]
Caused by: java.lang.NoSuchMethodError: com.saxonica.config.ProfessionalConfiguration.internalSetBooleanProperty(Lnet/sf/saxon/lib/Feature;Ljava/lang/Object;)V
at com.saxonica.config.ProfessionalConfiguration.setConfigurationProperty(ProfessionalConfiguration.java:265) ~[na:na]
at com.saxonica.config.ProfessionalConfiguration.setConfigurationProperty(ProfessionalConfiguration.java:254) ~[na:na]
at net.sf.saxon.Configuration.init(Configuration.java:651) ~[oxygen-patched-saxon-9he-21.1.0.2.jar:na]
at net.sf.saxon.Configuration.<init>(Configuration.java:432) ~[oxygen-patched-saxon-9he-21.1.0.2.jar:na]
at com.saxonica.config.ProfessionalConfiguration.<init>(ProfessionalConfiguration.java:133) ~[na:na]
at com.saxonica.config.ProfessionalTransformerFactory.<init>(ProfessionalTransformerFactory.java:25) ~[na:na]
... 15 common frames omitted
I do not understand what I miss, any idea ?

Regards,
Isabelle
Radu
Posts: 8991
Joined: Fri Jul 09, 2004 5:18 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Radu »

Hello Isabelle,

Problem with class loaders (your custom URLClassLoader in this case) is that they prefer to return the classes from the super class loader if they have already been loaded.
So in various places in Oxygen we use a class loader we call LateDelegationClassLoader which prefers to load classes from its JAR libraries instead of falling back on the parent class loader. I'm pasting below how the contents of our late delegation class loader look like:

Code: Select all

public class LateDelegationClassLoader extends URLClassLoader {

  public LateDelegationClassLoader(URL[] urls, ClassLoader parent) {
    super(urls, parent);
  }

  @Override
  public URL getResource(final String name) {
    return AccessController.doPrivileged(new PrivilegedAction<URL>() {
      /**
       * @see java.security.PrivilegedAction#run()
       */
      @Override
      public URL run() {
        
        // Try locally.
        URL url = findResource(name);
        if (url == null) {
          // Delegate to super.
          url = LateDelegationClassLoader.super.getResource(name);
        }
        
        return url;
      }
    });
  }

  @Override
  protected synchronized Class loadClass(String name, boolean resolve)
    throws ClassNotFoundException {

    // First, check if the class has already been loaded
    Class c = findLoadedClass(name);
    if (c == null) {
      if(delegateToParent(name)){
        // Delegate to super.
        c = super.loadClass(name, false);
      } else {
        // Try locally
        try {
          c = findClass(name);
        } catch (ClassNotFoundException e) {
          // Delegate to super.
          c = super.loadClass(name, false);
        }
      }
    }
    if (resolve) {
      resolveClass(c);
    }
    return c;
  }

  protected boolean delegateToParent(String className) {
    if(className.equals(getClass().getName())){
      //EXM-36639 Prefer having a single class loaded usually in the base class loader.
      //In this way we can use instanceof for example.
      return true;
    }
    return className.startsWith("java.") || className.startsWith("javax.swing.")
      // EXM-16043 XHive bootstrap needs xbean.jar which redefines the org.w3c.dom package.
        || className.startsWith("org.w3c.dom.")
        //EXM-24640 The unmarshalling in
        //ro.sync.xml.uriattributes.URIAttributesRepository.loadRepository(URL) 
        //fails if the xml-apis.jar is preferred to resolve these interfaces. 
        || className.startsWith("javax.xml.datatype.")
        || className.startsWith("javax.xml.parsers.")
        || className.startsWith("javax.xml.transform.")
        || className.startsWith("javax.xml.validation.")
        // EXM-24901 Documentum needs this package.
        || className.startsWith("javax.xml.namespace.")
        || className.startsWith("org.xml.sax.")
        // EXM-25938 XMLInputFactory requires com.ctc.wstx.stax.WstxInputFactory
        // so is best to use the interfaces from the JRE.
        || className.startsWith("javax.xml.stream.")
        // EXM-28502: JUnit needs the annotations to be loaded on the default 
        // classloader.
        || className.startsWith("org.junit.");
  }
  
  /**
   * @see java.net.URLClassLoader#getPermissions(java.security.CodeSource)
   */
  @Override
  protected PermissionCollection getPermissions(CodeSource codesource) {
    PermissionCollection perms = new java.security.Permissions();
    perms.add(new AllPermission());
    return perms;
  }
  
  @Override
  public Enumeration<URL> getResources(String name) throws IOException {
    Enumeration<URL> myResources = findResources(name);
    Enumeration<URL> superResources = super.getResources(name);
    if(myResources == null || !myResources.hasMoreElements()) {
      return superResources;
    } else {
      //Prefer to return my resources as the first ones.
      LinkedHashSet<URL> resources = new LinkedHashSet<URL>();
      while(myResources.hasMoreElements()) {
        resources.add(myResources.nextElement());
      }
      if(superResources != null) {
        while(superResources.hasMoreElements()) {
          URL url = superResources.nextElement();
          if(! resources.contains(url)) {
            resources.add(url);
          }
        }
      }
      return new Vector(resources).elements();
    }
  }
}
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hi Radu,

Thanks for your feedback.
I did not know about that fact.

I have integrated your class and it works fine now.
Thanks again.

Regards,
Isabelle
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello,

Thanks to you, we can compile XSL with Saxon PE in java but we still have issue.

We try to implement
Configuring Proposed Values in the Context that the Content Completion was Invoked
that we find here https://www.oxygenxml.com/doc/versions/ ... -proposals.

But when we launch our application and call content completion on an xml element, we have these error :

Code: Select all

60045 ERROR [ AWT-EventQueue-0 ] ro.sync.contentcompletion.xml.extensibility.values.g - javax.xml.transform.TransformerConfigurationException: E Errors were reported during stylesheet compilation
F Cannot find a 2-argument function named {http://saxon.sf.net/}expression(). Saxon extension functions are not available under Saxon-HE at line 18 and column 83
javax.xml.transform.TransformerConfigurationException: E Errors were reported during stylesheet compilation
F Cannot find a 2-argument function named {http://saxon.sf.net/}expression(). Saxon extension functions are not available under Saxon-HE at line 18 and column 83
	at ro.sync.exml.workspace.b.b.d.d(Unknown Source)
	at ro.sync.exml.workspace.b.b.d.c(Unknown Source)
	at ro.sync.exml.workspace.b.b.d.createXSLTTransformer(Unknown Source)
	at ro.sync.exml.workspace.b.b.d.createXSLTTransformer(Unknown Source)
	at ro.sync.contentcompletion.xml.extensibility.values.g.getValues(Unknown Source)
	at ro.sync.contentcompletion.xml.extensibility.values.b.filterAttributeValues(Unknown Source)
	at ro.sync.contentcompletion.xml.gb.oyr(Unknown Source)
	at ro.sync.contentcompletion.xml.db.i(Unknown Source)
	at ro.sync.contentcompletion.xml.y.rgs(Unknown Source)
	at ro.sync.contentcompletion.t.rgs(Unknown Source)
	at ro.sync.contentcompletion.editor.k.vwl(Unknown Source)
	at ro.sync.contentcompletion.editor.k.processKeyEvent(Unknown Source)
	at ro.sync.contentcompletion.editor.s.processKeyEvent(Unknown Source)
	at java.awt.Component.processEvent(Component.java:6310)
	at java.awt.Container.processEvent(Container.java:2236)
	at java.awt.Component.dispatchEventImpl(Component.java:4889)
	at java.awt.Container.dispatchEventImpl(Container.java:2294)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1954)
	at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:806)
	at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1074)
	at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:945)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:771)
	at java.awt.Component.dispatchEventImpl(Component.java:4760)
	at java.awt.Container.dispatchEventImpl(Container.java:2294)
	at java.awt.Window.dispatchEventImpl(Window.java:2746)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
	at java.awt.EventQueue$4.run(EventQueue.java:731)
	at java.awt.EventQueue$4.run(EventQueue.java:729)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Even if we have compiled our content completion with saxon pe, it calls saxon HE when it executes

Code: Select all

    <match elementName="property" attributeName="value">
      <xslt href="get_values.xsl" useCache="false" action="replace"/>
    </match>
Any ideas how to correct it ?

Regards,
Isabelle
alex_jitianu
Posts: 1007
Joined: Wed Nov 16, 2005 11:11 am

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by alex_jitianu »

Dear Isabelle,

You should remove this block from within the content completion configuration file:

Code: Select all

<match elementName="property" attributeName="value">
  <xslt href="get_values.xsl" useCache="false" action="replace"/>
</match>
No matter what you do, this XSLT will be executed with the built-in Saxon HE. What you need to do is to implement your own SchemaManagerFilter. In its filterAttributeValues method you will execute the XSLT with your own Saxon-PE processor. The XSLT needs some external parameters that you can obtain and pass like this:

Code: Select all

  
  /**
   * @see ro.sync.contentcompletion.xml.SchemaManagerFilter#filterAttributeValues(java.util.List, ro.sync.contentcompletion.xml.WhatPossibleValuesHasAttributeContext)
   */
  @Override
  public List<CIValue> filterAttributeValues(List<CIValue> attributeValues,
      final WhatPossibleValuesHasAttributeContext context) {
    
    
    ((net.sf.saxon.jaxp.TransformerImpl) transformer).setInitialTemplate("start");

    // Give parameters. systemID and location path.
    transformer.setParameter("documentSystemID", context.getSystemID());
    String contextXPathExpression = context.computeContextXPathExpression();
    if (contextXPathExpression != null) {
      transformer.setParameter("contextElementXPathExpression", contextXPathExpression);
    }
    transformer.transform(null, outputTarget);
Once you have this class, you pack it into a Jar, you put the Jar inside the Classpath of the framework and you specify the Schema Manager in the Extensions tab.

Please let me know if you need any additional details.

Best regards,
Alex
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello Alex,

Thanks a lot for your help.
It finally works.

Regards,
Isabelle
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello Alex,

As I said earlier, it works fine, but only on saved document, not on in worked / unsaved document.

Each time I asked for content completion, it used previous saved value or don't find new values.

Do you have any workaround for that ?

Regards,
Isabelle
alex_jitianu
Posts: 1007
Joined: Wed Nov 16, 2005 11:11 am

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by alex_jitianu »

Hello Isabelle,

If I understand it correctly, the XSLT file processes the saved version of the file, instead of the unsaved snapshot from the editor, right? If that's the case, then the fix is to set an URIResolver that will get the content from the editor, like this:

Code: Select all

    
    URIResolver uriResolver = PluginWorkspaceProvider.getPluginWorkspace().getXMLUtilAccess().getURIResolver();
    transformer.setURIResolver(uriResolver);
Best regards,
Alex
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello Alex,

Thanks for your answer.

I tried to implement it this way:

Code: Select all

		    System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
                    Source quomXslt = new StreamSource(ccSpecificCCValueConfigXslFile);
                    URIResolver uriResolver = PluginWorkspaceProvider.getPluginWorkspace().getXMLUtilAccess().getURIResolver();
                    Transformer quomTransformer = (Transformer) SaxonPEManager.getInstance().newSaxonPETransformer(quomXslt, "start");
                    quomTransformer.setURIResolver(uriResolver);
                    quomTransformer.setParameter("documentSystemID", context.getSystemID());
                    String contextXPathExpression = context.computeContextXPathExpression();
                    if (contextXPathExpression != null) {
                        quomTransformer.setParameter("contextElementXPathExpression", contextXPathExpression);
                    }
                    quomTransformer.transform(null, new StreamResult(ccSpecificCCValueConfigXmlFile));
But it still does not work.
Did I miss something ?

Regards,
Isabelle
alex_jitianu
Posts: 1007
Joined: Wed Nov 16, 2005 11:11 am

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by alex_jitianu »

Hello Isabelle,

To make sure I understand the situation correctly, the XSLT file processes the saved version of the file, instead of the unsaved snapshot from the editor, right?

The code looks O.K. Can you send me the zipped plugin on support@oxygenxml.com so I can reproduce the issue myself and look for a fix? After I finish my investigation, I will remove it from my system.

Best regards,
Alex
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello Alex,

You understand the situation correctly.
It never process the unsaved snapshot from the editor.
I don't know if I can send to you the plugin like that.

I will ask to my colleague, and let you know as soon as possible.

Regards,
Isabelle
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hi Everyone,

I have just send to support@oxygenxml.com all relevant files in order to have your help to solve our problem.
I can't send you our application, sorry, but I tried to send you all you need.

Here is a test case :

Code: Select all

<quantity quantityType="qty05">
   <quantityGroup quantityGroupType="minimum">
	  <quantityValue quantityUnitOfMeasure="um51">6.4</quantityValue>
	  <quantityValue quantityUnitOfMeasure="lbf.ft">47.2</quantityValue>
   </quantityGroup>
</quantity>
We want to filter quantityUnitOfMeasure attribute regarding the value of quantityType attribute.

Thanks,
Regards,
Isabelle
alex_jitianu
Posts: 1007
Joined: Wed Nov 16, 2005 11:11 am

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by alex_jitianu »

Dear Isabelle,

Thank you for taking the time to send us all those resources. It turns out that the API URIResolver doesn't pass though the opened editors, like I initially expected. Sorry about that... Luckily there is enough API available so that you can extend this behavior. Something like this:

Code: Select all

	private URIResolver creteResolver(String editorSystemId) {
		final URIResolver uriResolver = PluginWorkspaceProvider.getPluginWorkspace().getXMLUtilAccess().getURIResolver();
		
		return new URIResolver() {
			@Override
			public Source resolve(String href, String base) throws TransformerException {
				if (editorSystemId.equals(href)) {
					// Check if the file is opened inside an editor.
					WSEditor editorAccess = PluginWorkspaceProvider.getPluginWorkspace().getEditorAccess(new URL(editorSystemId), PluginWorkspace.MAIN_EDITING_AREA);
					if (editorAccess != null) {
						Reader reader = editorAccess.createContentReader();
						return new StreamSource(reader, editorSystemId);
					}
				}
				return uriResolver.resolve(href, base);
			}
		}; 
	}
Let me know how it goes!

Best regards,
Alex
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello Alex,

It works fine now !
Thanks a lot.

Regards,
Isabelle
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hi all,
Is this always true ?
alex_jitianu wrote: Thu Feb 23, 2017 4:53 pm In theory the XSLT should run just fine with Saxon-HE (which is available in the Author Component) as long as the XSLT doesn't use any functionality available only in the PE/EE versions. If you would need access to the element for which the CC was invoked, you will run into this issue (because saxon:eval() is not available in the HE version).

Code: Select all

        <xsl:variable name="propertyElement" 
            select="saxon:eval(saxon:expression($contextElementXPathExpression, ./*))"/>
Unfortunately there is no workaround for this other than using the Java API instead and implementing a SchemaManagerFilter.

Or can we use now your version of saxon to do saxon:eval query in 24.0.0.2 ?
If not, is it safe to exclude com.oxygenxml:oxygen-patched-saxon-9he:jar:24.0.0.2 thanks to maven to avoid ClassLoader issues ?
Thanks.

Regards,
Isabelle
alex_jitianu
Posts: 1007
Joined: Wed Nov 16, 2005 11:11 am

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by alex_jitianu »

Hello,

You can use xsl:evaluate from XSLT 3.0 which is supported by Saxon HE. The XSLT will look like this:

Code: Select all

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:saxon="http://saxon.sf.net/"
    exclude-result-prefixes="xs"
    version="3.0">
    
    <xsl:param name="documentSystemID" as="xs:string"></xsl:param>
    <xsl:param name="contextElementXPathExpression" as="xs:string"></xsl:param>
    
    <xsl:template name="start">
        <xsl:apply-templates select="doc($documentSystemID)"/>
    </xsl:template>
    
    <xsl:template match="/">
        <xsl:variable name="propertyElement" as="element()">
            <xsl:evaluate xpath="$contextElementXPathExpression" context-item="./*" as="element()"></xsl:evaluate>
        </xsl:variable>
        
        <items>
            <xsl:if test="$propertyElement/@name = 'color'">
                <item value='red'/>
                <item value='blue'/>  
            </xsl:if>
            <xsl:if test="$propertyElement/@name = 'shape'">
                <item value='rectangle'/>
                <item value='square'/>  
            </xsl:if>
        </items>
    </xsl:template>
</xsl:stylesheet>
Best regards,
Alex
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hi Alex,
Thanks for your answer.
I tried this :

Code: Select all

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:saxon="http://saxon.sf.net/"
    exclude-result-prefixes="xs"
    version="3.0">

  <xsl:param name="documentSystemID" as="xs:string"/>
  <xsl:param name="contextElementXPathExpression" as="xs:string"/>

  <xsl:template name="start">
    <xsl:apply-templates select="doc($documentSystemID)"/>
  </xsl:template>

  <xsl:template match="/">
    <xsl:variable name="propertyElement" as="element()">
      <xsl:evaluate xpath="$contextElementXPathExpression" context-item="./*" as="element()"></xsl:evaluate>
    </xsl:variable>

    <items>
      <xsl:if test="$propertyElement/ancestor::quantity/@quantityType = 'qty52'">
        <item value='F'/>
        <item value='pF'/>
        <item value='uF'/>
      </xsl:if>
      <xsl:if test="$propertyElement/ancestor::quantity/@quantityType = 'qty56'">
        <item value='Wb'/>
        <item value='mWb'/>
        <item value='uWb'/>
      </xsl:if>
      <xsl:if test="$propertyElement/ancestor::quantity/@quantityType = 'qty60'">
        <item value='F/m'/>
        <item value='uF/m'/>
      </xsl:if>
    </items>
  </xsl:template>

</xsl:stylesheet>
But I get this error

Code: Select all

net.sf.saxon.trans.XPathException: net.sf.saxon.trans.XPathException: xsl:evaluate is not available in this configuration
	at net.sf.saxon.expr.ErrorExpression.evaluateItem(ErrorExpression.java:138) ~[oxygen-patched-saxon-9he-24.0.0.2.jar:?]
Did I miss something ?

Thanks,
Regards,
Isabelle
alex_jitianu
Posts: 1007
Joined: Wed Nov 16, 2005 11:11 am

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by alex_jitianu »

Hi Isabelle,
I'm sorry about that, but it seems xsl:evaluate was introduced in Saxon HE 10 which we hope to integrate in Oxygen 24.1 (to be released in March). The current version of Oxygen bundles Saxon 9.9 in which xsl:evaluate is only available in the PE distribution. That being said, I think the only way is to implement a custom SchemaManagerFilter. The WhatPossibleValuesHasAttributeContext object that comes on the SchemaManagerFilter#filterAttributeValues() callback has all the API that you need:
- computeContextXPathExpression()
- executeXPath()

Best regards,
Alex
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hi Alex,

Thanks for the feedback.
alex_jitianu wrote: Thu Jan 20, 2022 11:32 am it seems xsl:evaluate was introduced in Saxon HE 10 which we hope to integrate in Oxygen 24.1 (to be released in March).
It will be a great improvement for us if Saxon HE 10 was integrated in the next version of Oxygen.

Regards,
Isabelle
tavy
Posts: 363
Joined: Thu Jul 01, 2004 12:29 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by tavy »

Hello Isabelle,

We just released Oxygen version 24.1.
The new version includes Saxon 10.6 as built-in transformer, as well as Saxon 10.7 and Saxon 11.2 as add-ons.

For the complete list of features, you can go to:
https://www.oxygenxml.com/xml_editor/wh ... SLT_XQuery

Best Regards,
Octavian
Octavian Nadolu
<oXygen/> XML Editor
http://www.oxygenxml.com
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hi,

Thanks for the feedback.
We will check that soon.

Regards,
Isabelle
Isabelle
Posts: 141
Joined: Fri Jan 20, 2017 1:11 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Isabelle »

Hello,

For information with oxygen 25.0, the xsl:evaluate method works fine.

Regards,
Isabelle
Radu
Posts: 8991
Joined: Fri Jul 09, 2004 5:18 pm

Re: Configuring Proposed Values in the Context that the Content Completion was Invoked - SAXON

Post by Radu »

Hi Isabelle,
Thanks for updating the post!
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Post Reply