【问题标题】:How to deal with XML namespaces如何处理 XML 命名空间
【发布时间】:2011-09-05 12:45:22
【问题描述】:

我觉得这个问题很简单,但我已经有好几年没有做任何 xslt 了,所以也许有人可以帮忙?

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

xml 的 sn-p 如下所示:

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

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

谁能告诉我访问 (a) 帐户名称和 (b) 代理名称的 xpath 吗?我认为了解如何访问这些可能会让我访问我需要的所有其他内容。

非常感谢, 皮特

【问题讨论】:

    标签: xml xslt namespaces transform xml-namespaces


    【解决方案1】:

    如果您打算使用 XML,那么值得一试命名空间——尽管这可能会很痛苦。从长远来看,推迟理解只会让事情变得更加痛苦。

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

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

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

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

    当 xmlns 属性单独指定一个值时(即您看到 xmlns="something"),这意味着命名空间是此元素及其后代的效果(除非在更深层次)。

    因此,在您的示例文档(有点像命名空间大杂烩)中,根 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>

    【讨论】:

    • 感谢 Alex,其中有几个有效点。说实话,我上一次使用 xml 可能已经有 10 年了,所以这不是我经常做的事情。客户要求我解决的特定问题涉及在某事发生时从基于对象的系统发送电子邮件。从记忆来看,序列化所涉及的对象(您所指的大杂烩是由 .net 的内置序列化程序之一提供)然后对其进行转换并将生成的 html 推送到邮件正文中似乎是一个好主意。
    • 很棒的命名空间解释。
    【解决方案2】:

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

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

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

    更好地查看您的输入,您有父命名空间。您需要选择元素的正确命名空间。例如AccountAgentgrbd 范围内,而Namegrba 范围内。在命名空间声明之后,您可以选择如下:

    //grbd:Account/grba:Name
    

    //grbd:Agent/grba:Name
    

    这对于带有前缀命名空间的元素是正确的。否则你应该选择本地的。例如对于第一个Id 节点,您需要:

    //gbd:Id
    

    【讨论】:

    • 是的,我现在开始明白了。看起来一般规则是为每个元素添加其命名空间的前缀。
    • 欢迎。我在答案中添加了详细信息,因为第一个解决方案不是使用命名空间的正确方法。
    【解决方案3】:

    【讨论】:

    • 感谢 Shilaghae 的这个链接,看起来不错的文章可以打印出来离线阅读。
    猜你喜欢
    • 2013-04-11
    • 2011-07-07
    • 2014-05-31
    • 2011-05-14
    • 2021-08-02
    • 2016-11-25
    • 1970-01-01
    • 2018-06-11
    相关资源
    最近更新 更多