XML元素名带有冒号

26

我正在使用一个第三方的xml api。他们定义了一个类似于以下结构的必需的xml结构。

<ns1:E xmlns:ns1="schema">
<ns1:B>
    <ns2:S>
        <ns2:V>
            <ns2:Bl />
        </ns2:V>
    </ns2:S>
</ns1:B>
</ns1:E>

我有一个SQL表格,里面包含需要转换成XML格式的信息。我使用 LINQ to SQL 适配器来获取数据,并且使用 System.Xml 创建XML文档。

XmlDocument.CreateElement("ns1:E"); etc

如果我从元素名称中删除冒号,这个方法就可以正常工作。有了冒号,只有冒号右侧的内容才是元素名称。我知道冒号是不允许的,但我无法控制第三方API的规定。

有什么办法可以解决这个问题吗?是否有一些有用的方法可以强制把冒号放入元素名称中?我不一定非要使用XMLDocument,但不确定还有什么其他方法可以达到目的。

更新:我意识到<ns1:是指命名空间,而且有两个。在编写XML时,如果这样说,我可以让它正常工作 -

 XmlDocument.CreateElement("ns1:E", "http://schema");

然而,这个的XML输出结果是

<ns1:E xmlns:ns1="http://schema">
如果我只是这样说: XmlDocument.CreateElement("ns1:E");没有uri,那么输出结果只是<E>。我不想让输出结果有模式引用,但我确实需要前缀。我想要实现的结果就是简单的<ns1:E>。这两个命名空间都在顶部声明,我认为这意味着我必须在每个节点上声明它们。
6个回答

15

2
我也遇到了同样的问题,即使使用这种方法也无法解决。你是如何实现简单的ns1:E的? - Eternal Noob

8

冒号表示这些元素在ns1命名空间内。 当您使用多个模式时,这是必需的。 假设文档仅使用ns1,则本质上等同于在这些标记中没有任何“ns1:”。

有关更多信息,请参见此指南


4
实际上,那些冒号表示元素在“schema”命名空间中。 ns1不是命名空间,它是命名空间的缩写。它可以更改;命名空间的名称则不能更改,否则将成为不同的命名空间。 - Robert Rossney

6
您所发布的XML文档实际上不是格式良好的,因为分配给许多元素的缩写ns2未与命名空间相关联。修正后,它可能看起来像这样:
<ns1:E xmlns:ns1="schema" xmlns:ns2="my-namespace">
  <ns1:B>
    <ns2:S>
      <ns2:V>
        <ns2:Bl />
       </ns2:V>
    </ns2:S>
  </ns1:B>
</ns1:E>

上述XML文档在语义上等同于以下文档:
<s:E xmlns:s="schema">
  <s:B>
    <S xmlns="my-namespace">
      <m:V xmlns:m="my-namespace">
        <s:Bl xmlns:s="my-namespace"/>
      </m:V>
    </S>
  </s:B>
</s:E>

并且针对这个问题:

<E xmlns="schema">
  <B xmlns="schema">
    <S xmlns="my-namespace">
      <V>
        <Bl/>
      </V>
    </S>
  </B>
</E>

在这三种情况下,EB元素位于schema命名空间中,而SVBl元素位于my-namespace命名空间中。
命名空间前缀很有用,但严格来说并不必要。您可以创建像最后一个示例那样不使用前缀的XML文档,并为每个元素显式声明命名空间。
在处理XML时,如果您认为关心给定元素使用的前缀,那么您几乎肯定是错误的。您唯一需要关心的是它属于哪个命名空间。例如,如果我将任何这三个文档加载到XmlDocument中,则以下代码将写出“Bl”元素:
    XmlNamespaceManager ns = new XmlNamespaceManager(d.NameTable);
    ns.AddNamespace("a", "schema");
    ns.AddNamespace("b", "my-namespace");
    Console.Write(d.SelectSingleNode("/a:E/a:B/b:S/b:V/b:Bl", ns).OuterXml);

当你说:
“我不想让输出有模式引用,但我需要保留前缀。我想要实现的结果仅仅是 <ns1:E>。”
你几乎肯定是错的。带有标签ns1:E的元素在没有将ns1前缀映射到命名空间时是毫无意义的,无论是在该元素中还是在其祖先元素中。 (另外,命名空间并不是一个模式引用。)如果您使用的是...
CreateElement("ns1", "E", "schema");

创建元素并将其附加到已经声明ns1作为schema命名空间前缀的元素上,然后DOM将附加该元素而不带命名空间声明,因为在这种情况下它是不需要的。如果ns1未声明(或声明为缩写其他命名空间而非schema),那么DOM将添加一个命名空间声明和前缀到该元素中。
简而言之:您关心命名空间,而不是命名空间前缀。

3
我知道这是一个老问题,但我正在做类似的事情,并找到了如何解决它的方法。我正在记录下来以便以后查找。
string myName = "foo";
// 获取本地和x命名空间 string ns_local = root.GetNamespaceOfPrefix("local"); string ns_x = root.GetNamespaceOfPrefix("x");
// 创建一个名为MyTag的本地元素节点 System.Xml.XmlNode newNode = doc.CreateNode(System.Xml.XmlNodeType.Element, "local", "MyTag", ns_local);
// 创建一个名为Key的属性节点 System.Xml.XmlNode attr = doc.CreateNode(System.Xml.XmlNodeType.Attribute, "Key", ns_x); attr.Value = myName; newNode.Attributes.SetNamedItem(attr);
// 创建一个名为MyAttr的属性节点 attr = doc.CreateNode(System.Xml.XmlNodeType.Attribute, "MyAttr", ""); attr.Value = myName; newNode.Attributes.SetNamedItem(attr);
// 将新节点添加到指定节点的子节点列表末尾 nodeToAppendTo.AppendChild(newNode);
这将给我一个看起来像这样的标签:
<local:MyTag x:Key="foo" MyAttr="foo" />

迄今为止这里最好的实际例子。 - vapcguy

2
<ns1:E xmlns:ns1="schema">
    <ns1:B>
       <ns2:S>
         <ns2:V>
           <ns2:Bl />
         </ns2:V>
       </ns2:S>
    </ns1:B>
</ns1:E>

如果要使用Create XmlElement来获得上述输出,则可按以下方式实现:

CreateElement("ns1","E", "schema");
CreateElement("ns1","B", "schema");
CreateElement("ns2","S", "schema");
CreateElement("ns2","V", "schema");
CreateElement("ns2","B1", "schema");

在这里,元素“E”是根元素,因此它会将其与模式一起前缀为“ns1”。

由于所有其他提到的元素(如“B”,“S”,“V”,“B1”)都是“E”的子元素,因此它使用提到的前缀为子元素添加前缀,但不再显示子元素的模式。

因此,您将获得所需的输出,其中包括根元素中的模式和子元素中的前缀。


1

冒号前的单词是命名空间。如果你想要一个元素"ns1:E",你需要创建一个名为"E"的元素,并将其命名空间设置为"ns1"。


谢谢,我明白了,但是我还没有得到我想要的结果。不确定为什么。如果我指定一个URI或NS引用,元素名称是正确的,但它会将引用添加到输出中,这不是我想要的。如果我不指定,前缀就不会被添加。 - nelsonwebs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接