2012-09-25 31 views
8

Tôi nhận được hàng ngàn tệp XML sau tất cả cùng một lược đồ/cấu trúc. Tôi đã triển khai IXmlSerializable và do đó tôi tự đọc các yếu tố và thuộc tính..NET XML Deserialization bỏ qua các không gian tên

Vấn đề của tôi là các tệp này từng sử dụng một không gian tên giả mạo khác nhau. Các tệp này đến từ một nguồn khác vì vậy tôi không thể thay đổi điều đó: D Ngoài ra, có quá nhiều không gian tên cho tôi để xây dựng một mảng các không gian tên có thể và chuyển nó đến xmlserializer.

Ngay bây giờ, nếu tôi không chỉ định vùng tên, nó sẽ gửi lỗi [xmlns: ns0 = "http://tempuri.org/abcd.xsd" không được mong đợi].

Tôi muốn có thể nói trình nối tiếp chỉ đơn giản là bỏ qua không gian tên khi deserializing đối tượng của tôi và chỉ cháy ReadXML. Hoặc chỉ có thể nói nó chấp nhận bất kỳ không gian tên "http://tempuri.org/" nào.

Điều đó có khả thi không?

Tôi muốn tránh sửa đổi tệp càng nhiều càng tốt.

Cảm ơn bạn!

+1

Bạn có cân nhắc việc tải XML trước để có được không gian tên để sau đó bạn có thể chuyển nó vào XmlSerializer không? –

+0

@StevenDoggart Vâng tôi đã làm, nhưng tôi muốn biết nếu có một cách "thích hợp" hơn để làm điều này trước khi tôi bắt đầu làm việc xung quanh nó. Nó chỉ có vẻ ngớ ngẩn mà bạn không thể bỏ qua không gian tên mà không nhận được một ngoại lệ: S – user1698428

+0

Vâng, đó là một câu hỏi rất tốt và tôi rất tò mò nếu có một câu trả lời cho nó là tốt. –

Trả lời

0

Đây không phải là câu trả lời cho câu hỏi của bạn về cách nói cho XmlSerialiser bỏ qua các không gian tên nhưng giải pháp thay thế. Bạn có thể sử dụng phép biến đổi xslt để tách các không gian tên khỏi xml trước khi tuần tự hóa nó.

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

Một vài phương pháp khuyến nông như những người giúp đỡ cho việc này, sẽ có một chút khó khăn để có được tất cả chúng có thể nhưng tôi sẽ cố gắng:

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

bạn có thể xóa không gian tên từ file xml bằng cách sử dụng mã này

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

Có, có thể. Khi bạn gọi phương thức Deserialize của XmlSerializer, bạn có thể chỉ định một cá thể XmlTextReader.

This answer by Cheeso on a related C# question cho biết cách tạo XmlTextReader bỏ qua mọi không gian tên xuất hiện trong tệp XML. Tôi đã lấy sự tự do để dịch ý tưởng của mình để VB và tạo ra một đơn giản proof-of-concept dụ dựa trên yêu cầu của bạn:

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 

Lưu ý: Nếu nó chỉ là tài liệu của không gian tên mặc định đó là khác nhau (ví dụ: các thẻ riêng lẻ không có các không gian tên khác nhau), sử dụng một tiêu chuẩn TextXmlReader với thuộc tính Namespaces được đặt thành 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 
Các vấn đề liên quan