代码之家  ›  专栏  ›  技术社区  ›  Tim Jarvis

属性上的Xelement默认命名空间提供意外行为

  •  3
  • Tim Jarvis  · 技术社区  · 15 年前

    我在创建包含默认名称空间和命名名称空间的XML文档时遇到问题,很难解释为什么只显示我正在尝试生成的内容…

    <Root xmlns="http://www.adventure-works.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:SchemaLocation="http://www.SomeLocatation.Com/MySchemaDoc.xsd">
      <Book title="Enders Game" author="Orson Scott Card" />
      <Book title="I Robot" author="Isaac Asimov" />
    </Root>
    

    但我最后得到的是…

    <Root xmlns="http://www.adventure-works.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:SchemaLocation="http://www.SomeLocatation.Com/MySchemaDoc.xsd">
      <Book p3:title="Enders Game" p3:author="Orson Scott Card" xmlns:p3="http://www.adventure-works.com" />
      <Book p3:title="I Robot" p3:author="Isaac Asimov" xmlns:p3="http://www.adventure-works.com" />
    </Root>
    

    我为生成这个XML代码段而编写的代码是…

      XNamespace aw = "http://www.adventure-works.com";
      XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
      XElement root = new XElement(aw + "Root",
          new XAttribute("xmlns", "http://www.adventure-works.com"),
          new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
          new XAttribute(xsi + "SchemaLocation", "http://www.SomeLocatation.Com/MySchemaDoc.xsd"),
    
          new XElement(aw + "Book",
            new XAttribute(aw + "title", "Enders Game"),
            new XAttribute(aw + "author", "Orson Scott Card")),
          new XElement(aw + "Book",
            new XAttribute(aw + "title", "I Robot"),
            new XAttribute(aw + "author", "Isaac Asimov")));
    

    基于一个 example on MSDN

    ***编辑***

    好吧,通过更多的实验,我现在对XML名称空间的工作方式非常困惑……

    如果我取消了AW+的致敬,我会得到我想要的……但现在看来,我想要的并不是我所期望的。我认为名称空间是从其父级继承的,属性也是这样吗?因为,这个读取属性的代码并不像我预期的那样工作…

      XElement xe = XElement.Parse(textBox1.Text);
      XNamespace aw = "http://www.adventure-works.com";
      var qry = from x in xe.Descendants(aw + "Book")
                select (string)x.Attribute(aw + "author");
    

    但是,如果删除属性上的aw+,则会导致我假设在默认名称空间中不能有属性。这是正确的吗?

    2 回复  |  直到 8 年前
        1
  •  6
  •   Jon Skeet    15 年前

    问得好。我挖了一点,发现 this bit of the XML spec :

    默认命名空间声明 适用于所有未准备的元素 其范围内的名称。违约 命名空间声明不适用 直接指向属性名;属性名 未准备的解释 属性由 它们出现的元素。

    稍后将给出以下示例:

    例如,每个坏的空元素标记在以下位置都是非法的:

    <!-- http://www.w3.org is bound to n1 and n2 -->
    <x xmlns:n1="http://www.w3.org" 
       xmlns:n2="http://www.w3.org" >
      <bad a="1"     a="2" />
      <bad n1:a="1"  n2:a="2" />
    </x>
    

    但是,以下每一项都是合法的,第二个是因为默认命名空间不适用于属性名:

    <!-- http://www.w3.org is bound to n1 and is the default -->
    <x xmlns:n1="http://www.w3.org" 
       xmlns="http://www.w3.org" >
      <good a="1"     b="2" />
      <good a="1"     n1:a="2" />
    </x>
    

    因此,基本上,属性名在默认情况下似乎不获取名称空间,这解释了您所看到的一切:)

        2
  •  1
  •   Thomas Freudenberg    13 年前
    XElement doc = XElement.Parse(ToXml());
    doc.DescendantsAndSelf().Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
    var ele = doc.DescendantsAndSelf();
    foreach (var el in ele)
        el.Name = ns != null ? ns + el.Name.LocalName : el.Name.LocalName;
    

    对于那些花了两天时间试图找到答案的人来说。