如何处理XML命名空间

时间:2011-05-31 13:57:04

标签: xml xslt namespaces transform xml-namespaces

我有一种感觉,这个问题非常简单,但是自从我做了任何xslt以来已经有好几年了,所以也许有人可以提供帮助?

我有一块由.net类DataContractSerializer生成的xml,我需要使用xslt从这个xml中提取数据,最后得到一些html。对我来说复杂的事情是命名空间的大量使用......

xml的片段如下所示:

<FundDeal xmlns:i="http://www.w3.org/2001/XMLSchema-instance"  xmlns="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Deal">
    <Id xmlns="http://schemas.datacontract.org/2004/07/Guide.BusinessObjects.Deal">DEAL12345</Id>
    <Account xmlns:d2p1="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
        <d2p1:AlternateId i:nil="true"/>
        <d2p1:Designation>XXX</d2p1:Designation>
        <d2p1:Name>QWERTY</d2p1:Name>
        <d2p1:Number>12345678</d2p1:Number>
        <d2p1:Status i:nil="true"/>
    </Account>
    <Agent xmlns:d2p1="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
        <d2p1:Id>54321</d2p1:Id>
        <d2p1:Name>ASDFG</d2p1:Name>
        <d2p1:Status>Active</d2p1:Status>
    </Agent>
    ....
</FundDeal>

现在,我需要通过样式表来转换这个xml,并且发现它非常艰难。我认识到xsl需要自己引用所涉及的命名空间,并且可以使用以下xsl轻松提取上面的Deal Id之类的内容:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ms="urn:schemas-microsoft-com:xslt"
    xmlns:grbd="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Deal"
    xmlns:gbd="http://schemas.datacontract.org/2004/07/Guide.BusinessObjects.Deal"
    xmlns:grba="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
    <xsl:output indent="yes" omit-xml-declaration="yes" method="html"/>
    <xsl:template match="/">
      <html>
        <head>
          <!-- some styles here -->
        </head>
        <body>
          <table cellpadding="5" cellspacing="5" border="0">
            <tr>
              <td class="SectionTitle" colspan="2">
                <xsl:text>Deal Cancellation Notification - </xsl:text>
                <xsl:value-of select="//ggbd:Id"/>
              </td>
            </tr>
          </table>
        </body>
      </html>
    </xsl:template>
</xsl:stylesheet>   

但我正在努力阅读诸如帐户名之类的内容,因为似乎有多个名称空间正在进行中。

任何人都可以告诉我访问的xpath(a)帐户名称,以及(b)代理商名称?我认为看到如何访问这些可能会让我访问我需要的所有其他内容。

非常感谢, 皮特

3 个答案:

答案 0 :(得分:5)

如果你打算使用XML,那么值得深入了解一下命名空间 - 这可能是痛苦的。从长远来看,推迟你的理解只会让事情变得更加痛苦。

帐户名称或代理名称没有“多个名称空间”:元素最多只能在一个命名空间中。

您看到的大多数命名空间语法仅仅是命名空间名称(URI)的绑定名称空间前缀。所以,当你看到

xmlns:i="http://www.w3.org/2001/XMLSchema-instance"

这将前缀“i”绑定到URI“http://www.w3.org/2001/XMLSchema-instance”,因此文档中更深层的元素可能会使用“i”前缀(基本上是保存击键的方法)。

当xmlns属性本身指定了一个值时(即你看到xmlns =“something”),这意味着Namespace是该元素及其后代的一个效果(除非被另一个命名空间覆盖更深层次。)

因此,在您的示例文档(有点像Namespace hodge-podge)中,根FundDeal元素的命名空间名称是“http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects .Deal“,这也是其子Account和Agent元素的情况(虽然它们恰好定义了命名空间/前缀绑定,但影响他们自己的命名空间:这个绑定由他们的孩子使用元件)。

您可以通过绑定自己的前缀(下面示例中的“fund”和“deal”)来最容易地在样式表中指定命名空间,以引用您需要的命名空间(我添加了更多内容,我希望它更多有点清楚):


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fund="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Deal"
  xmlns:deal="http://schemas.datacontract.org/2004/07/Guide.BusinessObjects.Deal"
  xmlns:d2p1="http://schemas.datacontract.org/2004/07/Guide.Rx.BusinessObjects.Account">
  <xsl:output indent="yes" omit-xml-declaration="yes" method="html"/>
  <xsl:template match="/">
    <html>
      <head>
        <!-- some styles here -->
      </head>
      <body>
        <table cellpadding="5" cellspacing="5" border="0">
          <tr>
            <td class="SectionTitle" colspan="2">
              <xsl:text>Deal Cancellation Notification - </xsl:text>
              <xsl:value-of select="/fund:FundDeal/deal:Id"/>
              <br/>
              <xsl:text>Account Name - </xsl:text>
              <xsl:value-of select="/fund:FundDeal/fund:Account/d2p1:Name"/>
              <br/>
              <xsl:text>Agent Name - </xsl:text>
              <xsl:value-of select="/fund:FundDeal/fund:Agent/d2p1:Name"/>
            </td>
          </tr>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:2)

这会起作用,但这不是正确的方法:

 //*[local-name()='Account']/grba:Name

 //*[local-name()='Agent']/grba:Name

更好地查看输入,您有父命名空间。您需要选择元素的正确名称空间。例如,AccountAgent位于grbd范围内,而Name位于grba中。在命名空间声明后,您可以选择如下:

//grbd:Account/grba:Name

//grbd:Agent/grba:Name

对于具有前缀命名空间的元素,情况属实。否则你应该选择本地的。例如,对于第一个Id节点,您需要:

//gbd:Id

答案 2 :(得分:1)