我需要通过XSLT翻译XML代码(在某些元素上添加和附加名称空间值),这在大多数情况下似乎都可以正常工作。但是,我遇到了以下代码的问题:
XML:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<PatientLookupResponse xmlns="urn:Epic-com:EMPI.2012.Services.Patient">
<PatientLookupResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Patients>
<Addresses>
</Addresses>
<HistoricalIDs/>
</Patients>
</PatientLookupResult>
</PatientLookupResponse>
</s:Body>
</s:Envelope>
XLST:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="urn:Epic-com:EMPI.2012.Services.External">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="HistoricalIDs">
<HistoricalIDs xmlns:a="urn:Epic-com:EMPI.2012.Services.External">
<xsl:apply-templates select="@*|node()"/>
</HistoricalIDs>
</xsl:template>
<xsl:template match="HistoricalIDs/IDType">
<a:IDType>
<xsl:apply-templates select="@*|node()"/>
</a:IDType>
</xsl:template>
<xsl:template match="HistoricalIDs/IDType/ID">
<a:ID>
<xsl:apply-templates select="@*|node()"/>
</a:ID>
</xsl:template>
<xsl:template match="HistoricalIDs/IDType/Type">
<a:Type>
<xsl:apply-templates select="@*|node()"/>
</a:Type>
</xsl:template>
</xsl:stylesheet>
结果:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<PatientLookupResponse xmlns="urn:Epic-com:EMPI.2012.Services.Patient">
<PatientLookupResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Patients>
<Addresses>
</Addresses>
<HistoricalIDs/>
</Patients>
</PatientLookupResult>
</PatientLookupResponse>
</s:Body>
</s:Envelope>
我需要让结果XML返回<HistoricalIDs xmlns:a="urn:Epic-com:EMPI.2012.Services.External"/>
。问题是它使该元素与原始消息中的元素相同。当<PatientLookupResponse xmlns="urn:Epic-com:EMPI.2012.Services.Patient">
和</PatientLookupResponse>
不在原始邮件中时,翻译会起作用。但是,当该元素存在时,不会进行翻译。如何使用当前原始消息获得正确的翻译?
答案 0 :(得分:0)
问题在于PatientLookupResponse
...
<PatientLookupResponse xmlns="urn:Epic-com:EMPI.2012.Services.Patient">
这上面声明了一个默认命名空间,这意味着PatientLookupResponse
元素和所有后代节点(除非被覆盖)属于该命名空间。这意味着HistoricalIDs
也是该命名空间的一部分,属于命名空间的节点与具有不属于命名空间的同名节点不同。
解决方案是在您的XSLT中声明名称空间,并使用您选择的前缀:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a="urn:Epic-com:EMPI.2012.Services.External"
xmlns:p="urn:Epic-com:EMPI.2012.Services.Patient"
然后使用该命名空间前缀来匹配该命名空间中的节点
<xsl:template match="p:HistoricalIDs">
但是,当您执行此操作时,您可能会发现HistoricalIDs
输出如下:
<HistoricalIDs xmlns="" xmlns:a="urn:Epic-com:EMPI.2012.Services.External"/>
这是因为您在输出中创建了一个新的HistoricalIDs
元素,该元素没有名称空间。因此,您也可以在创建输出时使用名称空间前缀:
<xsl:template match="p:HistoricalIDs">
<p:HistoricalIDs xmlns:a="urn:Epic-com:EMPI.2012.Services.External">
<xsl:apply-templates select="@*|node()"/>
</p:HistoricalIDs>
</xsl:template>
或者您也可以在XSLT中声明一个默认命名空间,这将适用于您输出的任何没有前缀的元素
试试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a="urn:Epic-com:EMPI.2012.Services.External"
xmlns:p="urn:Epic-com:EMPI.2012.Services.Patient"
exclude-result-prefixes="p">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p:HistoricalIDs" xmlns="urn:Epic-com:EMPI.2012.Services.Patient">
<HistoricalIDs xmlns:a="urn:Epic-com:EMPI.2012.Services.External">
<xsl:apply-templates select="@*|node()"/>
</HistoricalIDs>
</xsl:template>
<xsl:template match="p:HistoricalIDs/p:IDType">
<a:IDType>
<xsl:apply-templates select="@*|node()"/>
</a:IDType>
</xsl:template>
<xsl:template match="p:HistoricalIDs/p:IDType/p:ID">
<a:ID>
<xsl:apply-templates select="@*|node()"/>
</a:ID>
</xsl:template>
<xsl:template match="p:HistoricalIDs/p:IDType/p:Type">
<a:Type>
<xsl:apply-templates select="@*|node()"/>
</a:Type>
</xsl:template>
</xsl:stylesheet>