如何检测SOAP消息中是否存在名称空间前缀

时间:2015-09-22 14:17:42

标签: java xpath soap

我正在开发一个Java应用程序,它接受来自许多不同远程客户端的SOAP / HTTP Web服务请求。

我无法控制这些客户端以及它们如何构建SOAP请求。

我必须从这些SOAP请求消息中提取多个关键XML元素及其相关数据。

有些客户端在所有标签上使用名称空间前缀,而其他客户端则没有。

有没有办法可以检测到我收到的每个SOAP Request消息(或子文档)中是否存在名称空间前缀?

1 个答案:

答案 0 :(得分:1)

正如其他人已经评论过的那样,名称空间前缀并不重要:

  

在具有命名空间的XML中,元素或属性名称是限定名称,即它们由命名空间和本地名称部分组成,命名空间由前缀标识,用冒号与本地名称分隔。如果前缀为空,则没有冒号,并且该名称被称为默认名称空间,如果前缀为非空,则根据其范围内命名空间绑定将该名称称为名称空间(属性)类似于xmlns开头的声明。

前缀本身与名称的标识无关。命名空间和本地部分很重要。以下所有示例都具有rootenvelope的相同限定名称,即使它们具有不同的前缀:

<root>
  <envelope xmlns="urn:envelopes" />
</root>

<root xmlns:env="urn:envelopes">
  <env:envelope/>
</root>

<root xmlns:soap="urn:envelopes">
  <soap:envelope xmlns="urn:envelopes" />
</root>

<root xmlns:soap="urn:envelopes">
  <envelope xmlns="urn:envelopes" />
</root>

<root xmlns:soap="urn:envelopes">
  <foobar:envelope xmlns:foobar="urn:envelopes" />
</root>

虽然可以编写一个依赖于前缀的XPath表达式,但不建议这样做,并且只要有效文档到达时使用不同的前缀就会中断。

  

有没有办法可以检测到我收到的每个SOAP Request消息(或子文档)中是否存在名称空间前缀?

但是,有时候,了解文档中使用的命名空间很方便。获取前缀对此没有帮助,但它有时可以帮助分析错误。

如果您可以使用XPath 2.0,那么您可以使用简单的单行程序来查找文档中的所有名称空间:

distinct-values((//* | @*)/in-scope-prefixes(.))

虽然这将回答您的问题,但名称空间重新声明将导致返回一个前缀,该前缀实际上绑定到多个名称空间。要获取所有唯一名称,即前缀+冒号+本地名称,您可以使用:

distinct-values((//* | @*)/name(.))

要在XPath 1.0中获取相同的信息有点戏剧性,因为没有distinct-values并且路径表达式的rh-side不能返回非节点项。相反,我建议使用一点XSLT 1.0,很容易用Java实现(或者,选择所有节点并使用普通Java迭代它们):

<xsl:template match="* | @*">
    <xsl:if test="not(self::*)">@</xsl:if>
    <xsl:value-of select="name()" />
    <xsl:if test="namespace-uri()">
        <xsl:value-of select="concat(' uses &quot;', namespace-uri(), '&quot;')" />
    </xsl:if>
    <xsl:text>&#xA;</xsl:text>
    <xsl:apply-templates select="* | @*" />
</xsl:template>

或者,如果您真的只需要前缀,则会转储带有前缀和关联命名空间的名称:

<xsl:template match="*[contains(name(), ':')] | @*[contains(name(), ':')]">
    <xsl:if test="not(self::*)">@</xsl:if>
    <xsl:value-of select="concat(name(), ' uses &quot;', namespace-uri(), '&quot;')" />
    <xsl:text>&#xA;</xsl:text>
    <xsl:apply-templates select="* | @*" />
</xsl:template>

<xsl:template match="*" ><xsl:apply-templates select="* | @*"/></xsl:template>

<xsl:template match="text() | @*" />