XML for Web Service:内联附件

时间:2009-04-01 20:37:28

标签: java web-services xslt base64 attachment

我必须使用单个参数(XML格式的String)调用Web服务。 我正在通过XSLT转换构建它。到现在为止还挺好。

问题在于这个XSD片段:

<xs:complexType name="Document">
    <xs:sequence>
        <xs:element name="title" type="xs:string" minOccurs="1"/>
        <xs:element name="content" type="xs:base64Binary" minOccurs="1"/>
    </xs:sequence>
</xs:complexType>

将(例如)翻译成此XML:

<attachment>
    <title>test title</title>
    <content>          
    PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Inllc
    yI/Pg0KPG1zZ3ByYXRpY2E+DQogICAgPHByYXRpY2E+DQogICAgICAgIDxwcm9jZXNzbz
    4NCiAgICAgICAgICAgIDxjb2RQcm9jZXNzbz4xPC9jb2RQcm9jZXNzbz4NCiAgICAgICA
    gICAgIDxjb2RJc3RhbnphUHJvY2Vzc28MzwvY29kSXN0YW56YVByb2Nlc3NvPg0KICAgI
    CAgICAgICAgPGNvZFN0YXRvPjYwPC9jb2RTdGF0bz4NCiAgICAgICAgPC9wcm9jZXNzbz
    4NCiAgICA8L3ByYXRpY2E+DQo8L21zZ3ByYXRpY2E+
    </content>
</attachment>

是的,你做得对:我必须以64位二进制格式将文件内容插入到XML文档中。

我考虑过使用XSLT插入一个占位符,然后处理XML文档以将其替换为实际文件内容,但我想知道是否有针对这些场合的最佳实践,也许一些花哨的XSTL技巧远远超出我的知识或者一些可能派上用场的Java工具。

你会怎么做?

注意:我不能将 SOAP与附件一起使用,而且我很清楚前面提到的方法在附件很大的情况下很容易失败,但是我们的对手不会让步的那一刻。

4 个答案:

答案 0 :(得分:2)

执行此操作的最佳方法可能是读取文件并使用实例化XSLT转换的代码在base64中对其内容进行编码。 base64字符串可以作为参数传递给转换,也可以通过扩展方法请求转换。

原则上,XSLT可用于对base64 进行编码,但有些字节值,如0(对于XML 1.0和XML 1.1),以及29个低于0x20的其他代码(对于XML 1.0)被禁止作为XML文档中的字符,这使得XSLT中的这种编码变得不可能。

(见:http://projects.ischool.washington.edu/tabrooks/545/ContentManagement/PassingParameters.htm

答案 1 :(得分:1)

如果您的SOAP堆栈支持MTOM,请启用它。然后,将在内容元素中将“引用”放入将放置数据的MIME附件中。该数据可以是完全二进制的而不是base64编码的。

答案 2 :(得分:0)

这不是您正在寻找的答案,但像Woodstox link text这样的XML处理器支持有效读取和编写内联Base64编码内容。 使用Woodstox 4.0,它使用所谓的Typed Access API完成,它是Stax2扩展API的一部分(在“org.codehaus.stax2.typed。*”包下,TypedXMLStreamReader,TypedXMLStreamWriter)。

这允许在给定二进制数据的情况下流式读取/写入元素和属性值。

然后技巧就是用XSLT来解决这个问题。另一种可能更简单的方法是弄清楚客户端API Soap堆栈(如CXF aka XFire)是否可以通过XMLStreamReader / Writer访问内容。大多数新的都基于Stax,通常嵌入Woodstox。

答案 3 :(得分:0)

以下是我如何使用Java在base64Binary对象(使用MTOM或SwAref)上发送数据的方式,至少是出于测试目的(如硬编码数据路径所示)。

obj.setContent(
  new DataHandler(
    new URLDataSource(
      this.getClass().getResource("/someDocument.png")
    ));

虽然正常操作是使用FileDataSource传递数据。虽然我很确定有人会想到只创建自己的数据源。一般来说,我认为这是一个坏主意,因为最可能的实现是使用ByteArrayInputStream,它使用VM内存,如果你发送一个大文件会严重爆炸。

如果您需要传递一个简单的字符串用于测试目的,您可以执行以下操作:

obj.setContent(
  new DataHandler("test string", "text/plain");

此外,如果您正在使用WebSphere 7运行时,如果您发现正在发送的数据仅包含消息但没有附件,则可能需要在服务实现中使用@MTOM注释。

相关问题