我无法从命名空间的 XML 中选择节点值



我在将 SOAP 响应 XML 转换为纯文本字符串时遇到问题。我从XLST开始,我已经阅读了我能读到的所有内容。显然我需要完成的很简单,但所有示例都比我的上下文简单得多。

首先,我将访问返回此 XML 结构的 Web 服务(必应地图反向地理编码):

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <ReverseGeocodeResponse xmlns="http://dev.virtualearth.net/webservices/v1/geocode/contracts">
      <ReverseGeocodeResult xmlns:a="http://dev.virtualearth.net/webservices/v1/geocode" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <BrandLogoUri xmlns="http://dev.virtualearth.net/webservices/v1/common">
          http://dev.virtualearth.net/Branding/logo_powered_by.png
        </BrandLogoUri>
        <ResponseSummary xmlns="http://dev.virtualearth.net/webservices/v1/common">
          <AuthenticationResultCode>ValidCredentials</AuthenticationResultCode>
          <Copyright>(...)</Copyright>
          <FaultReason i:nil="true" />
          <StatusCode>Success</StatusCode>
          <TraceId>(...)</TraceId>
        </ResponseSummary>
        <a:Results xmlns:b="http://dev.virtualearth.net/webservices/v1/common">
          <b:GeocodeResult>
            <b:Address>
              <b:AddressLine>(...)</b:AddressLine>
              <b:AdminDistrict>SP</b:AdminDistrict>
              <b:CountryRegion>Brasil</b:CountryRegion>
              <b:District />
              <b:FormattedAddress>(...)</b:FormattedAddress>
              <b:Locality>Campinas</b:Locality>
              <b:PostalCode>13069-380</b:PostalCode>
              <b:PostalTown />
            </b:Address>
            <b:BestView>(...)</b:BestView>
            <b:Confidence>Medium</b:Confidence>
            <b:DisplayName>(...)</b:DisplayName>
            <b:EntityType>Address</b:EntityType>
            <b:Locations>(...)</b:Locations>
            <b:MatchCodes xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
              <c:string>Good</c:string>
            </b:MatchCodes>
          </b:GeocodeResult>
          <b:GeocodeResult>
            (...)
          </b:GeocodeResult>
        </a:Results>
      </ReverseGeocodeResult>
    </ReverseGeocodeResponse>
  </s:Body>
</s:Envelope>

节点b:GeocodeResult重复约 10 次。其他具有(...)的部分不相关(没有相关节点)。从这个广泛的响应中,我唯一需要的是节点b:Localityb:AdminDistrict。在过去的几天里,我一直在努力完成这项工作。

以下是众多方法之一:

<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns="http://dev.virtualearth.net/webservices/v1/common"
        xmlns:a="http://dev.virtualearth.net/webservices/v1/geocode"
        xmlns:b="http://dev.virtualearth.net/webservices/v1/common"
        xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
        xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <xsl:template match="/s:Envelope/s:Body/ReverseGeocodeResponse/ReverseGeocodeResult/a:Results/b:GeocodeResult/b:Address">
        <xsl:value-of select="b:Locality"/> - <xsl:value-of select="b:AdminDistrict"/>
    </xsl:template>
</xsl:stylesheet>

我知道这应该只返回前 b:Locality 个节点和b:AdminDistrict节点,这是完美的。但是当我尝试这样做时,结果是 XML 中的所有文本(根本没有标签,只是串联的文本)。此方法的某些变体仅返回两个 xsl:value-of 标记之间的 ' - ' 片段。

我做错了什么?这是否与命名空间的无限性有关?

样式

表中发生了什么

原始代码中发生的情况是这样的:您编写的一个模板与输入 XML 中的任何内容都不匹配。这意味着永远不会执行此模板中的代码。相反,对于输入 XML 中的所有节点,将应用默认的内置模板

内置模板遍历树,除了所有文本内容外,不输出任何其他内容。这就是为什么你最终得到:

但是当我尝试这样做时,结果是 XML 中的所有文本(根本没有标签,只是串联的文本)。

若要防止这种情况,请编写一个匹配所有文本的空模板:

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

然后,您可以立即更清楚地看到模板根本没有应用(无输出)和给出错误结果(错误输出)之间的区别。

为什么这会发生在您的样式表中?

模板与任何内容都不匹配,因为您的路径表达式:

/s:Envelope/s:Body/ReverseGeocodeResponse/ReverseGeocodeResult/a:Results/b:GeocodeResult/b:Address"

与输入 XML 中的任何节点都不匹配。对于上面的路径表达式,XPath 处理器期望ReverseGeocodeResponseReverseGeocodeResult不在命名空间中。但是对于您的输入 XML,情况并非如此:

<ReverseGeocodeResponse xmlns="http://dev.virtualearth.net/webservices/v1/geocode/contracts">
    <ReverseGeocodeResult xmlns:a="http://dev.virtualearth.net/webservices/v1/geocode">

ReverseGeocodeResponse 元素上,有一个默认命名空间 - 在这种情况下也适用于此元素本身。此外,它还会导致其子元素ReverseGeocodeResult采用此命名空间。

对此的解决方案

在 XSLT 样式表中声明此命名空间 ( http://dev.virtualearth.net/webservices/v1/geocode/contracts ),并为具有它的两个元素添加前缀。我知道您试图通过以下方式模仿输入 XML 的默认命名空间:

<xsl:stylesheet version="1.0"
    xmlns="http://dev.virtualearth.net/webservices/v1/common">

但效果不同。这将为 XSLT 样式表中的元素定义默认命名空间。但是您要做的是为 XPath 表达式定义一个默认命名空间。这也可以通过xpath-default-namespace - 这

  • 不幸的是,仅在 XSLT 2.0 中可用
  • 没有用,因为输入 XML 具有多个默认命名空间

样式表

<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:a="http://dev.virtualearth.net/webservices/v1/geocode"
        xmlns:b="http://dev.virtualearth.net/webservices/v1/common"
        xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:con="http://dev.virtualearth.net/webservices/v1/geocode/contracts">
    <xsl:output method="text"/>
    <xsl:template match="/s:Envelope/s:Body/con:ReverseGeocodeResponse/con:ReverseGeocodeResult/a:Results/b:GeocodeResult/b:Address">
        <xsl:value-of select="b:Locality"/> - <xsl:value-of select="b:AdminDistrict"/>
    </xsl:template>
    <xsl:template match="text()"/>
</xsl:stylesheet>

文本输出

Campinas - SP

您看到的 xml jumble是由于内置模板的默认处理规则。通常,如果只想处理文档中的特定元素,则需要捕获根元素,然后有选择地使用apply-templates

此外,您没有看到预期值的原因是ReverseGeocodeResponseReverseGeocodeResult实际上是 xmlns 命名空间http://dev.virtualearth.net/webservices/v1/geocode/contracts - 您需要适当调整 xslt (我添加了别名 zz):

<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns="http://dev.virtualearth.net/webservices/v1/common"
        xmlns:a="http://dev.virtualearth.net/webservices/v1/geocode"
        xmlns:b="http://dev.virtualearth.net/webservices/v1/common"
        xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
        xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:zz="http://dev.virtualearth.net/webservices/v1/geocode/contracts">
  <xsl:template match="/">
    <xsl:apply-templates select="/s:Envelope/s:Body/zz:ReverseGeocodeResponse/zz:ReverseGeocodeResult/a:Results/b:GeocodeResult/b:Address"/>
  </xsl:template>
  <xsl:template match="b:Address">
    <xsl:value-of select="b:Locality"/> - <xsl:value-of select="b:AdminDistrict"/>
  </xsl:template>
</xsl:stylesheet>

相关内容

  • 没有找到相关文章

最新更新