XSLT匹配XML元素转换

时间:2015-04-24 03:08:17

标签: xml web-services xslt soap

我需要通过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>不在原始邮件中时,翻译会起作用。但是,当该元素存在时,不会进行翻译。如何使用当前原始消息获得正确的翻译?

1 个答案:

答案 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>