【问题标题】:How to detect presence of namespace prefixes in SOAP messages如何检测 SOAP 消息中命名空间前缀的存在
【发布时间】:2015-09-23 05:18:35
【问题描述】:

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

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

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

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

有什么方法可以检测到我收到的每个 SOAP 请求消息(或子文档)中是否存在命名空间前缀?

【问题讨论】:

  • 其实没关系,只要文件有效就行。
  • 请举例说明您需要接受的文件类型。每个的前几行应该足够了。通常,名称空间 prefixes 无关紧要,但所有 SOAP 请求都必须位于 SOAP 标准指定的名称空间中。所以你同样可以忽略前缀,只在正确的命名空间中寻找元素。

标签: java xpath soap


【解决方案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 请求消息(或子文档)中是否存在命名空间前缀?

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

如果您可以使用 XPath 2.0,那么您可以使用一个简单的单行代码来查找文档中的所有命名空间:

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

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

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

使用 XPath 1.0 获得相同的信息有点戏剧性,因为没有 distinct-values 并且路径表达式的 rh 侧不能返回非节点项。相反,我建议使用一点 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() | @*" />

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-12
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    相关资源
    最近更新 更多