2010-12-02 12 views
11

Estoy utilizando Linq a XML para crear un nuevo archivo XML. Alguna parte del archivo obtengo de un archivo XML existente. Yo uso el siguiente código para esto.XElement agrega un xmlns

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 

El problema es que agrega xmlns = "" el primer elemento del archivo existente.

El resultado es:

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

El archivo XML que estoy leyendo de las miradas de este tipo, pero puedo cambiarlo si es necesario

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

Respuesta

11

Estás viendo esto porque el elemento de configuración (presumiblemente proveniente de su documento) no vive en este espacio de nombres. Vive en el espacio de nombres predeterminado/null-uri.

Necesitará transformar su documento de entrada para cambiar su espacio de nombre.

Este ejemplo un tanto simplificada tomar su archivo XML y lo coloca en otro documento, pero, antes de hacerlo, cambia el espacio de nombres de todos los elementos de ese archivo XML a la de su documento de destino ...

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());    
    } 

el resultado de la cual esta ...

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

como se puede ver, el elemento de configuración se encuentra ahora en el mismo espacio de nombres como el elemento foo. Esto es esencialmente una transformación xml rápida y sucia, y claramente no respeta ningún espacio de nombres en el documento XML que está importando. Pero esto podría ser lo que está buscando, o podría al menos formar la base de algo más sólido.

+0

Entiendo eso, pero ¿cómo puedo hacer eso? He intentado defaultSettings.Name = ns + defaultSettings.Name.LocalName; Pero debo hacerlo para todos los subelementos. Debe ser algo mejor. – magol

+0

o necesita transformar el documento utilizando técnicas Xslt, o leer cada elemento y transformarlo en código. Básicamente, el XDocument que ha cargado conoce el espacio de nombres de cada elemento en ese documento, y sabe que no es el mismo espacio de nombres que foo. –

+0

¿Puedo cambiar el archivo xml del que leí para que aparezca en el pseudónimo correcto? – magol

1

Puede escribir un método de extensión para esto. Este método tiene un valor de retorno por lo que admite el encadenamiento, pero también cambia la transformación del original para que pueda usarse sin asignación.

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