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

标签 java xpath soap

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

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

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

某些客户端在所有标记上使用命名空间前缀,而其他客户端则不使用。

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

最佳答案

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

In XML with namespaces, an element or attribute name are qualified names, that is, they consist of a namespace and a local name part, with the namespace identified by a prefix, separated by a colon from the local name. If the prefix is empty, there is no colon and the name is said to be in the default namespace, if the prefix is non-empty, the name is said to be in the namespace according to its in-scope namespace binding (the attribute-like declarations starting with 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 表达式,但不建议这样做,并且一旦使用不同前缀的有效文档到达,就会中断。

Is there any way I can detect the presence of namespace prefixes within each SOAP Request message (or sub document) I receive?

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

如果您可以使用 XPath 2.0,则可以使用一个简单的单行代码来查找文档中的所有 namespace :

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

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

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

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

关于java - 如何检测 SOAP 消息中是否存在命名空间前缀,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32719373/

相关文章:

xpath - Google表格中的ImportXML函数产生错误“导入的内容为空”!

xml - EXSL-如何使用str:tokenize()?

java - 客户端传输异常 : The server sent HTTP status code 302: Found

java - 将 HTTP header 添加到 JAX-WS 服务响应

java - 为什么 "Clone a linked list with next and random pointer"的这个解的空间复杂度是 O(1) ?

Java正则表达式转换

sql-server - where 子句中的 .exist 和 .value 哪个更快?

Java 正则表达式、匹配模式、词对

java - ExceptionTranslator 的异常不会返回到 flex

SOAP:指向的命名空间不再存在。可能的后果?