2012-09-25 15 views
8

Ho ottenuto migliaia di file XML seguendo lo stesso schema/struttura. Ho implementato IXmlSerializable e quindi sto leggendo gli elementi e gli attributi.La deserializzazione XML ignora gli spazi dei nomi

Il mio problema è che questi file utilizzano uno spazio dei nomi diverso. Questi file provengono da un'altra fonte, quindi non posso cambiarlo: D Inoltre, ci sono troppi di questi spazi dei nomi per me per creare semplicemente un array di possibili spazi dei nomi e passarlo a xmlserializer.

In questo momento, se non si specifica uno spazio dei nomi, viene generato un errore [xmlns: ns0 = "http://tempuri.org/abcd.xsd] non previsto.

Mi piacerebbe essere in grado di dire al serializzatore di ignorare semplicemente lo spazio dei nomi quando deserializzare il mio oggetto e basta leggere ReadXML. O solo essere in grado di dirgli di accettare qualsiasi spazio dei nomi "http://tempuri.org/".

È possibile?

Vorrei evitare di modificare i file il più possibile.

Grazie!

+1

Avete considerato di caricare prima l'XML per ottenere lo spazio dei nomi in modo da poterlo passare in XmlSerializer? –

+0

@StevenDoggart Sì, ma vorrei sapere se esiste un modo più "appropriato" per farlo prima di iniziare a lavorarci. Sembra sciocco che tu non possa ignorare gli spazi dei nomi senza ottenere un'eccezione: S – user1698428

+0

Sì, è un'ottima domanda e sono molto curioso di sapere se c'è una risposta anche a questo. –

risposta

0

Non è una risposta alla tua domanda su come dire a XmlSerialiser di ignorare i namespace ma una soluzione alternativa. È possibile utilizzare una trasformazione xslt per rimuovere gli spazi dei nomi dal xml prima di serializzarlo.

<?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 paio di metodi di estensione come aiutanti per questo, sarà un po 'difficile da farli tutti forse, ma ci proverò:

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

è possibile rimuovere gli spazi dei nomi dal file XML utilizzando questo codice

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ì, è possibile. Quando chiami il metodo Deserialize del tuo XmlSerializer, puoi specificare un'istanza XmlTextReader.

This answer by Cheeso on a related C# question mostra come creare un XmlTextReader che ignora tutti gli spazi dei nomi che si verificano nel file XML. Mi sono preso la libertà di tradurre la sua idea di VB e creare un semplice esempio proof-of-concept in base alle proprie esigenze:

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: Se è solo spazio dei nomi predefinito del documento che è diverso (ovvero, i singoli tag non hanno spazi dei nomi diversi), utilizzando uno standard TextXmlReader con la proprietà Namespaces impostata su False.

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