我无法将SOAP响应XML转换为纯文本字符串。 我从XLST开始,我已经阅读了所有可能的内容。显然我需要完成的工作很简单,但所有示例都比我的上下文简单。
首先,我正在访问一个返回此XML结构的Web服务(Bing Maps Reverse Geocoding):
<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:Locality
和b: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
标记之间的“ - ”片段。
我做错了什么?这可能与命名空间的无限性有关吗?
答案 0 :(得分:3)
样式表
原始代码中会发生这样的情况:您编写的一个模板不匹配输入XML中的任何内容。这意味着永远不会执行此模板中的代码。相反,对于输入XML中的所有节点,默认为built-in templates are applied。
内置模板遍历树,除了所有文本内容外,不输出任何内容。这就是为什么你最终得到:
但是当我尝试这个时,结果就是XML中的所有文本(根本没有标签,只是连接文本)。
要防止这种情况,请编写一个与所有文本匹配的空模板:
<xsl:template match="text()"/>
然后,您可以立即更清楚地看到模板之间完全没有应用(没有输出)和输出错误(输出错误)之间的区别。
为什么会在样式表中发生这种情况?
模板与任何内容都不匹配,因为您的路径表达式为:
/s:Envelope/s:Body/ReverseGeocodeResponse/ReverseGeocodeResult/a:Results/b:GeocodeResult/b:Address"
与输入XML中的任何节点都不匹配。对于上面的路径表达式,XPath处理器期望ReverseGeocodeResponse
和ReverseGeocodeResult
位于 no 名称空间中。但对于您的输入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
-
<强>样式表强>
<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
答案 1 :(得分:1)
您看到的jumble
xml是由内置模板的default processing rules引起的。通常,如果您只想处理文档中的特定元素,则需要捕获根元素,然后有选择地使用apply-templates
。
此外,您没有看到预期值的原因是因为ReverseGeocodeResponse
和ReverseGeocodeResult
实际上是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>