2009-01-25 13 views
8

Estoy tratando de usar System.Xml.Linq para crear documentos XHTML. Por lo tanto, la gran mayoría de los nodos en mis árboles debe utilizar este espacio de nombres:Cómo crear XElement con el espacio de nombres predeterminado para niños sin usar XNamespace en todos los nodos secundarios

http://www.w3.org/1999/xhtml 

puedo crear XElement nodos como alcance este espacio de nombres con bastante facilidad, utilizando un XNamespace, así:

XNamespace xhtml = "http://www.w3.org/1999/xhtml"; 
// ... 
new XElement(xhtml + "html", // ... 

Sin embargo, no quiero tener que hacer un XNamespace disponible en todo el código que crea nodos HTML, y tengo que ponerle un prefijo a cada uno de los nombres XElement (y XAttribute) que creo en consecuencia.

El formato de texto XML en sí tiene en cuenta este requisito, y permite establecer un espacio de nombre predeterminado en un antepasado heredado por descendientes, utilizando el atributo xmlns reservado. Me gustaría hacer algo similar usando System.Xml.Linq.

¿Esto es posible?

Respuesta

5

He decidido utilizar una clase estática llamada XHtml, que se ve así:

public static class XHtml 
{ 
    static XHtml() 
    { 
     Namespace = "http://www.w3.org/1999/xhtml"; 
    } 

    public static XNamespace Namespace { get; private set; } 

    public static XElement Element(string name) 
    { 
     return new XElement(Namespace + name); 
    } 

    public static XElement Element(string name, params object[] content) 
    { 
     return new XElement(Namespace + name, content); 
    } 

    public static XElement Element(string name, object content) 
    { 
     return new XElement(Namespace + name, content); 
    } 

    public static XAttribute Attribute(string name, object value) 
    { 
     return new XAttribute(/* Namespace + */ name, value); 
    } 

    public static XText Text(string text) 
    { 
     return new XText(text); 
    } 

    public static XElement A(string url, params object[] content) 
    { 
     XElement result = Element("a", content); 
     result.Add(Attribute("href", url)); 
     return result; 
    } 
} 

Ésta parece ser la manera más limpia de haciendo cosas, particularmente cuando puedo agregar en rutinas de conveniencia, como el método XHtml.A (no toda mi clase se muestra aquí).

+0

Esta solución parece pesada y aterradora, pero en realidad es agradable, liviana, extensible, hace que su código sea más corto y protege contra los errores tipográficos en los nombres de los elementos o atributos. ¡Guauu! –

+0

Acabo de entender por qué tiene todas estas ventajas. Si bien la pregunta solo decía "Quiero espacios de nombres automáticos", lo más simple y sensato es "Me gustaría tener algunos métodos abreviados que encapsulen algunos conocimientos básicos de HTML", cuyo efecto de espacio de nombres es solo un buen subproducto. –

1

El problema es que el XName utilizado para crear el XElement necesita especificar el espacio de nombre correcto. Lo que me gustaría tener la tentación de hacer es crear una clase estático como sigue: -

public static class XHtml 
{ 
    public static readonly XNamespace Namespace = "http://www.w3.org/1999/xhtml"; 
    public static XName Html { get { return Namespace + "html"; } } 
    public static XName Body { get { return Namespace + "body"; } } 
       //.. other element types 
} 

Ahora puede crear un documento XHTML como esto: -

XDocument doc = new XDocument(
    new XElement(XHtml.Html, 
     new XElement(XHtml.Body) 
    ) 
); 

Un enfoque alternativo a la clase estática sería : -

static class XHtml 
{ 
    public static readonly XNamespace Namespace = "http://www.w3.org/1999/xhtml"; 
    public static readonly XName Html = Namespace + "html"; 
    public static readonly XName Body = Namespace + "body"; 
} 

Esto tiene la desventaja de generar ejemplares de todos los posibles XName independientemente de si los usa, pero la ventaja es la conversión de espacio de nombre + "nombre de etiqueta" sólo ocurre una vez. No estoy seguro de que esta conversión se optimice de otra manera. Estoy seguro de que XNames son solamente una vez instanciado: -

XNamepace n = "http://www.w3.org/1999/xhtml"; 
XNames x = n + "A"; 
XName y = n + "A"; 
Object.ReferenceEquals(x, y) //is true. 
+0

Un tercer enfoque es volver a escribir el subárbol, html-node hacia abajo, antes de agregar a XDocument en la raíz. Soy consciente de estas otras formas de resolver el problema, me preguntaba si había una forma de evitarlo. Supongo que probablemente no. –

+0

Umm ... ¿eh? html-node abajo? No entiendo eso. Aún necesitaría usar XNames que tengan el espacio de nombres xhtml. – AnthonyWJones

+0

Anthony: se reescribe el árbol para incluir el espacio de nombres XHTML en los nombres que no tienen un espacio de nombres delimitado, es decir, se verifica XName.Namespace es XNamespace.None; por nodo html, me refiero al nodo raíz de los documentos XHTML. –

3

Tomé la ruta de reescritura recursiva. Realmente no tienes que 'reconstruir' el árbol. Puede simplemente cambiar los nombres de los nodos (XName).

private static void ApplyNamespace(XElement parent, XNamespace nameSpace) 
    { 
     if(DetermineIfNameSpaceShouldBeApplied(parent, nameSpace)) 
     { 
      parent.Name = nameSpace + parent.Name.LocalName; 
     } 
     foreach (XElement child in parent.Elements()) 
     { 
      ApplyNamespace(child, nameSpace); 
     } 
    } 
Cuestiones relacionadas