2012-09-25 27 views
8

Tengo miles de archivos XML siguiendo el mismo esquema/estructura. Implementé IXmlSerializable y, por lo tanto, estoy leyendo los elementos y atributos por mi cuenta..NET XML Deserialization ignora los espacios de nombres

Mi problema es que cada uno de estos archivos usa un espacio de nombre falso diferente. Estos archivos provienen de otra fuente, por lo que no puedo cambiar eso: D Además, hay demasiados espacios de nombres para que solo cree una matriz de los espacios de nombres posibles y los transfiera al xmlserializer.

En este momento, si no especifico un espacio de nombres, arroja un error [xmlns: ns0 = "http://tempuri.org/abcd.xsd" no esperado].

Me gustaría poder decirle al serializador que simplemente ignore el espacio de nombres al deserializar mi objeto y que simplemente ejecute ReadXML. O simplemente puede decirle que acepte cualquier espacio de nombres "http://tempuri.org/".

¿Es esto posible?

Me gustaría evitar la modificación de los archivos tanto como sea posible.

¡Gracias!

+1

¿Ha considerado cargar primero el XML para obtener el espacio de nombre para que luego pueda pasarlo al XmlSerializer? –

+0

@StevenDoggart Sí, lo hice, pero me gustaría saber si hay una forma más "adecuada" de hacerlo antes de empezar a trabajar en torno a esto. Parece una tontería que no puedas ignorar espacios de nombres sin obtener una excepción: S – user1698428

+0

Sí, es una muy buena pregunta y tengo mucha curiosidad si también hay una respuesta. –

Respuesta

0

No es una respuesta a su pregunta acerca de cómo decirle al XmlSerialiser que ignore los espacios de nombres, pero una solución alternativa. Puede usar una transformación xslt para quitar los espacios de nombres del xml antes de serializarlo.

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/|comment()|processing-instruction()"> 
    <xsl:copy> 
     <xsl:apply-templates/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*"> 
    <xsl:element name="{local-name()}"> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="@*"> 
    <xsl:attribute name="{local-name()}"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
    </xsl:template> 

</xsl:stylesheet> 

Un par de métodos de extensión como ayudantes para esto, va a ser un poco difícil de llegar a todos ellos, pero tal vez voy a tratar:

/// <summary> 
/// Transforms the xmldocument to remove all namespaces using xslt 
/// http://stackoverflow.com/questions/987135/how-to-remove-all-namespaces-from-xml-with-c 
/// http://msdn.microsoft.com/en-us/library/42d26t30.aspx 
/// </summary> 
/// <param name="xmlDocument"></param> 
/// <param name="indent"></param> 
public static XmlDocument RemoveXmlNameSpaces(this XmlDocument xmlDocument, bool indent = true) 
{ 
    return xmlDocument.ApplyXsltTransform(Properties.Resources.RemoveNamespaces, indent); 
} 

public static XmlDocument ApplyXsltTransform(this XmlDocument xmlDocument, string xsltString,bool indent= true) 
{ 
    var xslCompiledTransform = new XslCompiledTransform(); 
    Encoding encoding; 
    if (xmlDocument.GetEncoding() == null) 
    { 
     encoding = DefaultEncoding; 
    } 
    else 
    { 
     encoding = Encoding.GetEncoding(xmlDocument.GetXmlDeclaration().Encoding); 
    } 
    using (var xmlTextReader = xsltString.GetXmlTextReader()) 
    { 
     xslCompiledTransform.Load(xmlTextReader); 
    } 
    XPathDocument xPathDocument = null; 
    using (XmlTextReader xmlTextReader = xmlDocument.OuterXml.GetXmlTextReader()) 
    { 
     xPathDocument = new XPathDocument(xmlTextReader); 
    } 
    using (var memoryStream = new MemoryStream()) 
    { 
     using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings() 
      { 
       Encoding = encoding, 
       Indent = indent 
      })) 
     { 
      xslCompiledTransform.Transform(xPathDocument, xmlWriter); 
     } 
     memoryStream.Position = 0; 
     using (var streamReader = new StreamReader(memoryStream, encoding)) 
     { 
      string readToEnd = streamReader.ReadToEnd(); 
      return readToEnd.ToXmlDocument(); 
     } 
    } 
} 

public static Encoding GetEncoding(this XmlDocument xmlDocument) 
{ 
    XmlDeclaration xmlDeclaration = xmlDocument.GetXmlDeclaration(); 
    if (xmlDeclaration == null) 
     return null; 
    return Encoding.GetEncoding(xmlDeclaration.Encoding); 
} 

public static XmlDeclaration GetXmlDeclaration(this XmlDocument xmlDocument) 
{ 
    XmlDeclaration xmlDeclaration = null; 
    if (xmlDocument.HasChildNodes) 
     xmlDeclaration = xmlDocument.FirstChild as XmlDeclaration; 
    return xmlDeclaration; 
} 

public static XmlTextReader GetXmlTextReader(this string xml) 
{ 
    return new XmlTextReader(new StringReader(xml)); 
} 
0

se puede quitar espacios de nombres de archivo XML mediante el uso de este código

using (FileStream stream = new FileStream("FilePath",FileMode.Create)) 
       { 
        XmlSerializer serializer = new XmlSerializer(typeof(YourClass)); 
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
        ns.Add("", "");      
        serializer.Serialize(stream," Your Object to Serialize",ns); 
       } 
0

Sí, es posible. Cuando llame al método Deserialize de su XmlSerializer, puede especificar una instancia XmlTextReader.

This answer by Cheeso on a related C# question muestra cómo crear un XmlTextReader que ignora los espacios de nombres que se producen en el archivo XML. Me he tomado la libertad de traducir su idea de VB y crear un ejemplo simple prueba de concepto en función de sus necesidades:

Imports System.IO 
Imports System.Text 
Imports System.Xml 
Imports System.Xml.Serialization 

' Helper class 
Class NamespaceIgnorantXmlTextReader 
    Inherits XmlTextReader 

    Public Sub New(stream As Stream) 
     MyBase.New(stream) 
    End Sub 

    Public Overrides ReadOnly Property NamespaceURI As String 
     Get 
      Return "" 
     End Get 
    End Property 
End Class 

' Serializable class 
Public Class ExampleClass 
    Public Property MyProperty As String 
End Class 

' Example 
Module Module1 
    Sub Main() 
     Dim testXmlStream = New MemoryStream(Encoding.UTF8.GetBytes(
      "<ExampleClass xmlns=""http://tempuri.org/SomePhonyNamespace1.xsd"" 
          xmlns:ph2=""http://tempuri.org/SomePhonyNamespace2.xsd""> 
       <ph2:MyProperty>SomeValue</ph2:MyProperty> 
      </ExampleClass>")) 

     Dim serializer As New XmlSerializer(GetType(ExampleClass)) 
     Dim reader As New NamespaceIgnorantXmlTextReader(testXmlStream) 
     Dim example = DirectCast(serializer.Deserialize(reader), ExampleClass) 

     Console.WriteLine(example.MyProperty) ' prints SomeValue 
    End Sub 
End Module 

Nota: Si es sólo espacio de nombres por defecto del documento que es diferente (es decir, las etiquetas individuales no tienen espacios de nombres diferentes), usando un estándar TextXmlReader con la propiedad Namespaces establecida en False es suficiente.

Imports System.IO 
Imports System.Text 
Imports System.Xml 
Imports System.Xml.Serialization 

' Serializable Class 
Public Class ExampleClass 
    Public Property MyProperty As String 
End Class 

' Example 
Module Module1 
    Sub Main() 
     Dim testXmlStream = New MemoryStream(Encoding.UTF8.GetBytes(
      "<ExampleClass xmlns=""http://tempuri.org/SomePhonyNamespace1.xsd""> 
       <MyProperty>SomeValue</MyProperty> 
      </ExampleClass>")) 

     Dim serializer As New XmlSerializer(GetType(ExampleClass)) 
     Dim reader As New XmlTextReader(testXmlStream) 
     reader.Namespaces = False 
     Dim example = DirectCast(serializer.Deserialize(reader), ExampleClass) 

     Console.WriteLine(example.MyProperty) ' prints SomeValue 
    End Sub 
End Module 
Cuestiones relacionadas