2012-09-25 11 views
8

Ich habe Tausende von XML-Dateien nach dem gleichen Schema/Struktur. Ich habe IXmlSerializable implementiert und lese daher die Elemente und Attribute selbst..NET XML Deserialisierung ignorieren Namespaces

Mein Problem ist, dass diese Dateien jeweils einen anderen falschen Namespace verwenden. Diese Dateien stammen von einer anderen Quelle, daher kann ich das nicht ändern: D Außerdem gibt es zu viele dieser Namespaces für mich, um einfach ein Array der möglichen Namespaces zu erstellen und es an den xmlserializer zu übergeben.

Jetzt, wenn ich keinen Namespace angeben, wird ein [xmlns: ns0 = "http://tempuri.org/abcd.xsd" wurde nicht erwartet] Fehler.

Ich möchte in der Lage sein, den Serializer zu sagen, den Namespace einfach zu ignorieren, wenn ich mein Objekt deserialisiere und nur ReadXML feuere. Oder einfach nur sagen können, dass es den Namensraum "http://tempuri.org/" akzeptiert.

Ist das möglich?

Ich möchte vermeiden, die Dateien so viel wie möglich zu ändern.

Vielen Dank!

+1

Haben Sie in Betracht gezogen, zuerst das XML zu laden, um den Namespace zu erhalten, damit Sie ihn dann in den XmlSerializer eingeben können? –

+0

@StevenDoggart Ja, das habe ich getan, aber ich würde gerne wissen, ob es eine "geeignetere" Möglichkeit gibt, dies zu tun, bevor ich anfange, daran herumzuarbeiten. Es scheint einfach albern, dass man Namespaces nicht ignorieren kann, ohne eine Ausnahme zu bekommen: S – user1698428

+0

Ja, das ist eine sehr gute Frage und ich bin sehr neugierig, ob es auch eine Antwort darauf gibt. –

Antwort

0

Es ist keine Antwort auf Ihre Frage darüber, wie Sie dem XmlSerialiser mitteilen, Namespaces zu ignorieren, sondern eine Umgehungslösung. Sie können eine xslt-Transformation verwenden, um die Namespaces vor dem Serialisieren aus der XML-Datei zu entfernen.

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

Ein paar Erweiterungsmethoden als Helfer für diese, ein bisschen schwierig zu bekommen, sie alle vielleicht zu gehen, aber ich werde versuchen:

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

Sie Namespaces aus XML-Datei mithilfe entfernen Dieser Code

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

Ja, es ist möglich. Wenn Sie die Deserialize Methode Ihrer XmlSerializer aufrufen, können Sie eine XmlTextReader Instanz angeben.

This answer by Cheeso on a related C# question zeigt, wie Sie eine XmlTextReader erstellen, die alle Namespaces in der XML-Datei ignoriert. Ich habe die Freiheit genommen, seine Idee zu VB zu übersetzen und ein einfachen Proof-of-Concept-Beispiel auf Basis Ihre Anforderungen erstellen:

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 

Hinweis: Wenn es nur das Dokument Standard-Namespace, die anders ist (dh die einzelnen Tags haben keine unterschiedlichen Namensräume), wobei ein Standard TextXmlReader mit der Namespaces-Eigenschaft, die auf False gesetzt ist, ausreicht.