如何从 OSGi Bundle 中使用 Java 扩展执行 XSLT 转换

发布于 2024-12-03 22:17:20 字数 1566 浏览 0 评论 0原文

我们正在将现有代码转换为 OSGi 环境。在我们的(尚未成为的)OSGi 包之一中,我们有执行 XSLT 转换的代码。 XSLT 的一部分包含一个 Java 扩展函数来创建唯一的数值。 Java 类也驻留在包中。这是样式表的片段:

<xsl:template match="m:property">
   <xsl:variable name="uniqueDataStreamName" select="concat(../@id,'/',@name)" />
   <xsl:variable name="uniqueDataStreamId"
       select="java:com.xyz.TransformationUtils.makeDataStreamIdFromUniqueName($uniqueDataStreamName)" />
   <data id="{number($uniqueDataStreamId)}">
   <tag>
      <xsl:value-of select="$uniqueDataStreamName" />
   </tag>
   <current_value>
     <xsl:value-of select="@value" />
  </current_value>
</data>

作为参考,这是转换的设置和调用方式:

protected Templates createTemplates(Source xsltSource) {
    try {
        TransformerFactory tf = TransformerFactory.newInstance();
        Templates templates = tf.newTemplates(xsltSource);
        return templates;
    } catch (TransformerException e) {
        throw new RuntimeException(e);
    }
}


protected byte[] transform(byte[] input) throws TransformerException {
    ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
    templates.newTransformer().transform(
            new StreamSource(new ByteArrayInputStream(input)),
            new StreamResult(out));
    return out.toByteArray();
}

当在非 OSGi 环境中运行时,它可以工作。当在 OSGi 框架中运行时,它会失败,因为找不到类 TransformationUtils,因此无法编译样式表。我有点理解——加载 jaxp 转换器实现的类加载器在我们的包中看不到扩展类。然而,我很难找到解决方案。我尝试使用 OSGi:fied Xalan 和 Xerces 捆绑包,但没有成功。

我的问题是:如何解决这个问题?可以吗?

We are in the process of converting existing code to an OSGi environment. In one of our (yet to be) OSGi bundles we have code that perform an XSLT transformation. A piece of the XSLT includes a java extension function to create a unique numeric value. The Java class also resides within the bundle. This is a fragment of the style sheet:

<xsl:template match="m:property">
   <xsl:variable name="uniqueDataStreamName" select="concat(../@id,'/',@name)" />
   <xsl:variable name="uniqueDataStreamId"
       select="java:com.xyz.TransformationUtils.makeDataStreamIdFromUniqueName($uniqueDataStreamName)" />
   <data id="{number($uniqueDataStreamId)}">
   <tag>
      <xsl:value-of select="$uniqueDataStreamName" />
   </tag>
   <current_value>
     <xsl:value-of select="@value" />
  </current_value>
</data>

For reference, this is how the transformation is set up and called:

protected Templates createTemplates(Source xsltSource) {
    try {
        TransformerFactory tf = TransformerFactory.newInstance();
        Templates templates = tf.newTemplates(xsltSource);
        return templates;
    } catch (TransformerException e) {
        throw new RuntimeException(e);
    }
}


protected byte[] transform(byte[] input) throws TransformerException {
    ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
    templates.newTransformer().transform(
            new StreamSource(new ByteArrayInputStream(input)),
            new StreamResult(out));
    return out.toByteArray();
}

When run in a non OSGi environemnt, it works. When run in an OSGi framework, it fails because the stylesheet cannot be compiled because the class TransformationUtils cannot be found. I kind of understand that--the class loader loading the jaxp transformer implementation does not see the extension class in our bundle. However, I'm stumped at finding a solution. I've tried using OSGi:fied Xalan and Xerces bundles to no avail.

My question is: How can this be solved? Can it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

还如梦归 2024-12-10 22:17:20

答案取决于 XSLT 处理器如何查找扩展类。您可能需要阅读源代码和/或通过调试器运行它才能找到答案。

例如,如果 XSLT 处理器使用线程上下文类加载器 (TCCL),那么这通常会失败,因为 TCCL 在 OSGi 中未定义。您可以通过在调用 XSLT 处理器期间显式设置 TCCL 来解决此问题,例如:

ClassLoader orig = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());
try {
    // invoke XSLT processor
} finally {
    Thread.currentThread.setContextClassLoader(orig);
}

其中 MyClass 是捆绑包中的一个类,并且具有扩展类的可见性。

在最坏的情况下,处理器可能会使用自己的类加载器查找扩展,即通过简单地调用Class.forName()。在这里最好的办法就是痛打库的开发者,因为他们太愚蠢了。完成此操作后,您可以使用片段将扩展类附加到处理器包...这是一个令人讨厌的黑客,但比其他一些可能的讨厌的黑客更好。

The answer depends on how the XSLT processor looks up the extension class. You might need to read the source code and/or run it through a debugger to find this out.

For example, if the XSLT processor uses the Thread Context ClassLoader (TCCL) then this would normally fail because the TCCL is undefined in OSGi. You can work around this by explicitly setting the TCCL for the duration of the call to the XSLT processor, e.g.:

ClassLoader orig = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());
try {
    // invoke XSLT processor
} finally {
    Thread.currentThread.setContextClassLoader(orig);
}

where MyClass is a class from your bundle and has visibility of the extension class.

In the worst case, the processor might look up the extension using its own classloader, i.e. with a simple call to Class.forName(). The best thing to do here is to beat up the developer of the library for being so stupid. After you've done that, you could use a fragment to attach the extension class to the processor bundle... it's a nasty hack but better than some of the other possible nasty hacks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文