【问题标题】:XElement adds an xmlnsXElement 添加一个 xmlns
【发布时间】:2010-12-02 21:24:51
【问题描述】:

我正在使用 Linq to XML 创建一个新的 XML 文件。我从现有的 XML 文件中获取文件的某些部分。为此,我使用以下代码。

var v2 = new XDocument(
  new XDeclaration("1.0", "utf-16", ""),
  new XComment(string.Format("Converted from version 1. Date: {0}", DateTime.Now)),
  new XElement(ns + "keyem",
    new XAttribute(XNamespace.Xmlns + "xsd", xsd.NamespaceName),
    new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName),
    new XAttribute(xsi + "schemaLocation", schemaLocation.NamespaceName),
    new XAttribute("version", "2"),
    new XAttribute("description", description),
    new XElement(ns + "layout",
      new XAttribute("type", type),
      new XAttribute("height", height),
      new XAttribute("width", width),
      settings.Root)       // XML from an existing file

问题在于它从现有文件中添加了 xmlns = "" 的第一个元素。

结果是:

<?xml version="1.0" encoding="utf-16"?>
<foo 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://tempuri.org/KeyEmFileSchema.xsd KeyEmFileSchema.xsd"
  xmlns="http://tempuri.org/KeyEmFileSchema.xsd">
  <settings xmlns="">
      ...
  </settings>
</foo>

我正在读取的 XML 文件看起来像这样,但如果需要我可以更改它

<?xml version="1.0" encoding="utf-16"?>
<settings>
  <colormaps>
    <colormap color="Gray"     textcolor="Black"/>
    <colormap color="DarkGray" textcolor="White"/>
    <colormap color="Black"    textcolor="White"/>
    <colormap color="Cyan"     textcolor="Black"/>
  </colormaps>
  <macromaps>
    <macromap pattern="^@([0-9A-F]{2})\|([0-9A-F]{2})$"  replace="{ESC}$1{ESC}$2{MOUSERESET}"/>
    <macromap pattern="^\$([0-9A-F]{2})\|([0-9A-F]{2})$" replace="{USERCLICK}{ESC}$1{ESC}$2{MOUSERESET}"/>
    <macromap pattern="^\$([0-9A-F]{2})$"                replace="{USERCLICK}{ESC}$1"/>
  </macromaps>
  <keydefault color="Cyan"/>
  <groupdefault color="DarkGray"/>
</settings>

【问题讨论】:

    标签: c# xml linq linq-to-xml xml-namespaces


    【解决方案1】:

    您看到这一点是因为设置元素(可能来自您的文档)不在此命名空间中。它位于 default/null-uri 命名空间中。

    您需要转换输入文档才能更改其命名空间。

    这个稍微简化的示例将您的 xml 文件放入另一个文档中,但在此之前,它将该 xml 文件中每个元素的命名空间更改为目标文档的命名空间...

        static void ProcessXmlFile()
        {
            XNamespace ns = "http://tempuri.org/KeyEmFileSchema.xsd/";
    
            // load the xml document
            XElement settings = XElement.Load("data.xml");
    
            // shift ALL elements in the settings document into the target namespace
            foreach (XElement e in settings.DescendantsAndSelf())
            {
                e.Name = ns + e.Name.LocalName;
            }
    
            // write the output document
            var file = new XDocument(new XElement(ns + "foo",
                                            settings));
    
            Console.Write(file.ToString());            
        }
    

    这个结果……

    <foo xmlns="http://tempuri.org/KeyEmFileSchema.xsd/">
      <settings>
        <colormaps>
          <colormap color="Gray" textcolor="Black" />
          <colormap color="DarkGray" textcolor="White" />
          <colormap color="Black" textcolor="White" />
          <colormap color="Cyan" textcolor="Black" />
        </colormaps>
        <macromaps>
          <macromap pattern="^@([0-9A-F]{2})\|([0-9A-F]{2})$" replace="{ESC}$1{ESC}$2{MOUSERESET}" />
          <macromap pattern="^\$([0-9A-F]{2})\|([0-9A-F]{2})$" replace="{USERCLICK}{ESC}$1{ESC}$2{MOUSERESET}" />
          <macromap pattern="^\$([0-9A-F]{2})$" replace="{USERCLICK}{ESC}$1" />
        </macromaps>
        <keydefault color="Cyan" />
        <groupdefault color="DarkGray" />
      </settings>
    </foo>
    

    如您所见,settings 元素现在与 foo 元素位于相同的命名空间中。这本质上是一个快速而肮脏的 xml 转换,显然它不尊重您正在导入的 xml 文档中的任何命名空间。但这可能是您所追求的,或者至少可以构成更强大的东西的基础。

    【讨论】:

    • 我明白,但我该怎么做呢?我试过 defaultSettings.Name = ns+ defaultSettings.Name.LocalName;但我必须对所有子元素都这样做。一定是更好的东西。
    • 您要么需要使用 Xslt 技术转换文档,要么读取每个元素并在代码中转换它。基本上,您加载的 XDocument 知道该文档中每个元素的命名空间,并且知道它与 foo 不同的命名空间。
    • 我可以更改读取的 xml 文件以使其位于正确的名称空间中吗?
    • 你有设置xml的sn-p/sample吗?
    • 另外,您的代码示例无法编译。您是否删除了它的某些方面?第二行看起来不对。
    【解决方案2】:

    您可以为此编写扩展方法。 这个方法有一个返回值,所以它支持链接,但也改变了原来的转换,所以它可以在没有赋值的情况下使用。

    public static XElement EnsureNamespaceExists(this XElement xElement, XNamespace xNamespace)
    {
        string nodeName = xElement.Name.LocalName;
    
        if (!xElement.HasAttribute("xmlns"))
        {
            foreach (XElement tmpElement in xElement.DescendantsAndSelf())
            {
                tmpElement.Name = xNamespace + tmpElement.Name.LocalName;
            }
            xElement = new XElement(xNamespace + nodeName, xElement.FirstNode);
        }
    
        return xElement;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-01-18
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2014-08-28
      • 1970-01-01
      相关资源
      最近更新 更多