.NET XML反序列化忽略名称空间

.NET XML反序列化忽略名称空间,xml,vb.net,xml-serialization,xml-namespaces,Xml,Vb.net,Xml Serialization,Xml Namespaces,我得到了数千个遵循相同模式/结构的XML文件。 我实现了IXmlSerializable,因此我自己读取元素和属性 我的问题是,这些文件都使用不同的假名称空间。这些文件来自其他来源,因此我无法更改:D 而且,这些名称空间太多,我无法构建一个可能的名称空间数组并将其传递给xmlserializer 现在,如果我不指定名称空间,它会抛出一个[xmlns:ns0=”http://tempuri.org/abcd.xsd“未预期]错误 我希望能够告诉序列化程序在反序列化我的对象时忽略名称空间,而只触发R

我得到了数千个遵循相同模式/结构的XML文件。 我实现了IXmlSerializable,因此我自己读取元素和属性

我的问题是,这些文件都使用不同的假名称空间。这些文件来自其他来源,因此我无法更改:D 而且,这些名称空间太多,我无法构建一个可能的名称空间数组并将其传递给xmlserializer

现在,如果我不指定名称空间,它会抛出一个[xmlns:ns0=”http://tempuri.org/abcd.xsd“未预期]错误

我希望能够告诉序列化程序在反序列化我的对象时忽略名称空间,而只触发ReadXML。或者只是告诉它接受任何”http://tempuri.org/“名称空间

可能吗

我希望尽可能避免修改文件


谢谢大家!

这不是关于如何告诉XmlSerialiser忽略名称空间的问题的答案,而是一种解决方法。在序列化xml之前,可以使用xslt转换从xml中剥离名称空间

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

有两种扩展方法可以帮助实现这一点,可能需要一些技巧才能全部实现,但我会尝试:

/// <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));
}
//
///使用xslt转换xmldocument以删除所有名称空间
/// http://stackoverflow.com/questions/987135/how-to-remove-all-namespaces-from-xml-with-c
/// http://msdn.microsoft.com/en-us/library/42d26t30.aspx
/// 
/// 
/// 
公共静态XmlDocument RemoveXmlNameSpaces(此XmlDocument,bool indent=true)
{
返回xmlDocument.ApplyXsltTransform(Properties.Resources.RemoveNamespaces,indent);
}
公共静态XmlDocument ApplyXsltTransform(此XmlDocument XmlDocument,字符串xsltString,bool indent=true)
{
var xslcomiledtransform=新的xslcomiledtransform();
编码;
if(xmlDocument.GetEncoding()==null)
{
编码=默认编码;
}
其他的
{
encoding=encoding.GetEncoding(xmlDocument.getxmldesclaration().encoding);
}
使用(var xmlTextReader=xsltString.GetXmlTextReader())
{
xslCompiledTransform.Load(xmlTextReader);
}
XPathDocument XPathDocument=null;
使用(XmlTextReader=xmlDocument.OuterXml.GetXmlTextReader())
{
xPathDocument=新的xPathDocument(xmlTextReader);
}
使用(var memoryStream=new memoryStream())
{
使用(XmlWriter=XmlWriter.Create)(memoryStream,new XmlWriterSettings()
{
编码=编码,
缩进
}))
{
xslCompiledTransform.Transform(xPathDocument,xmlWriter);
}
memoryStream.Position=0;
使用(var streamReader=newstreamreader(memoryStream,encoding))
{
字符串readToEnd=streamReader.readToEnd();
返回readToEnd.ToXmlDocument();
}
}
}
公共静态编码GetEncoding(此XmlDocument XmlDocument)
{
XmlDeclaration=xmlDocument.GetXmlDeclaration();
if(xmlDeclaration==null)
返回null;
返回Encoding.GetEncoding(xmlDeclaration.Encoding);
}
公共静态XmlDeclaration GetXmlDeclaration(此XmlDocument XmlDocument)
{
XmlDeclaration=null;
if(xmlDocument.HasChildNodes)
xmlDeclaration=xmlDocument.FirstChild作为xmlDeclaration;
申报表;
}
公共静态XmlTextReader GetXmlTextReader(此字符串为xml)
{
返回新的XmlTextReader(新的StringReader(xml));
}

您可以使用此代码从xml文件中删除名称空间

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);
                }

是的,这是可能的。调用
XmlSerializer
反序列化
方法时,可以指定一个
XmlTextReader
实例

显示如何创建忽略XML文件中出现的任何名称空间的
XmlTextReader
。我冒昧地将他的想法转化为VB,并根据您的要求创建了一个简单的概念验证示例:

Imports System.IO
导入系统文本
导入System.Xml
导入System.Xml.Xml
'助手类
类NamespaceIgnorantXmlTextReader
继承XmlTextReader
公共子新建(流作为流)
MyBase.New(流)
端接头
Public将只读属性NamespaceURI重写为字符串
得到
返回“”
结束
端属性
末级
'可序列化类
公共类示例类
公共属性MyProperty作为字符串
末级
"比如,
模块1
副标题()
Dim testXmlStream=新内存流(Encoding.UTF8.GetBytes(
"
一些价值
"))
Dim序列化程序作为新的XmlSerializer(GetType(ExampleClass))
Dim读取器作为新的NamespaceIgnorantXmlTextReader(testXmlStream)
Dim示例=DirectCast(序列化程序.反序列化(读取器),ExampleClass)
Console.WriteLine(example.MyProperty)“打印一些值
端接头
端模块

注意:如果只是文档的默认名称空间不同(即,各个标记没有不同的名称空间),使用标准的
TextXmlReader
,并将
namespaces
属性设置为
False
就足够了

Imports System.IO
导入系统文本
导入System.Xml
导入System.Xml.Xml
'可序列化类
公共类示例类
公共属性MyProperty作为字符串
末级
"比如,
模块1
副标题()
Dim testXmlStream=新内存流(Encoding.UTF8.GetBytes(
"
一些价值
"))
Dim序列化程序作为新的XmlSerializer(GetType(ExampleClass))
Dim读卡器作为新的XmlTextReader(testXmlStream)
reader.namespace=False
Dim示例=DirectCast(序列化程序.反序列化(读取器),检查
/// <summary>
/// XML document reader replaces the namespace of the root element.
/// </summary>
public class MyXmlReader : Mvp.Xml.Common.XmlWrappingReader
{
    // Namespace of the document's root element. Read from document.
    private string rootNamespace = "";

    /// <summary>
    /// Get or set the target namespace to use when deserializing.
    /// </summary>
    public string TargetNamespace { get; set; }

    /// <summary>
    /// Initialize a new instance of the MXmlReader class.
    /// </summary>
    /// <param name="reader">XmlReader instance to modify.</param>
    public MyXmlReader(XmlReader reader) : base(reader)
    {
        TargetNamespace = "";
    }

    /// <summary>
    /// Return the namespace of the XML node. Substitute the target namespace if it matches the namespace of the root element.
    /// </summary>
    public override string NamespaceURI
    {
        get
        {
            if (Depth == 0 && NodeType == XmlNodeType.Element)
            {
                // Save the namespace from the document's root element.
                rootNamespace = base.NamespaceURI;
            }

            if (base.NamespaceURI == rootNamespace)
            {
                // Substitute the schema's targetNamespace for the root namespace.
                return TargetNamespace;
            }

            // Use the native namespace of the XML node.
            return base.NamespaceURI;
        }
    }
}
var reader = new MyXmlReader(XmlReader.Create(stream));
reader.TargetNamespace = "http://my.target.namespace";

// Deserialize using the defined XML attribute overrides that can
// supply XML serialization attributes to types at runtime.
Type t = typeof(SomeDeserializedObject);
var xo = SomeDeserializedObject.GetXmlAttributeOverrides();
XmlSerializer serializer = new XmlSerializer(t, xo);
SomeDeserializedObject o = (SomeDeserializedObject)serializer.Deserialize(reader);