这里有一些问题:
-
默认命名空间属性被添加到ReadOuterXml() 返回的字符串中,因为ReadOuterXml() 旨在不改变返回的 XML 的语义。显然,在您的 XML 中有一个 default namespace 应用于 <IWantThis> 的某个父节点——作为默认命名空间,它递归地应用于 <IWantThis> 本身。要保留此命名空间成员资格,ReadOuterXml() 在写出嵌套 XML 时必须发出默认命名空间。
如果你真的想完全忽略 XML 上的命名空间,你需要创建一个自定义的XmlReader,例如如图
-
您需要为SomeClass 构造一个XmlSerializer,其预期根节点为<IWantThis>。您可以使用XmlSerializer(Type, XmlRootAttribute) 构造函数执行此操作,但是,如果您这样做,您必须静态缓存并重用序列化程序以避免严重的内存泄漏,如 Memory Leak using StreamReader and XmlSerializer 中所述em>。
-
您正在创建要反序列化的元素的本地副本wantedNodeContents,然后重新解析该本地副本。无需这样做,您可以使用XmlReader.ReadSubtree() 来反序列化部分 XML。
将所有这些问题放在一起,您的GetObjectFromXml() 可能如下所示:
public static partial class XmlExtensions
{
public static T GetObjectFromXml<T>(string path, string localName, string namespaceURI, bool ignoreNamespaces = false)
{
using (var textReader = new StreamReader(path))
return GetObjectFromXml<T>(textReader, localName, namespaceURI);
}
public static T GetObjectFromXml<T>(TextReader textReader, string localName, string namespaceURI, bool ignoreNamespaces = false)
{
using (var xmlReader = ignoreNamespaces ? new NamespaceIgnorantXmlTextReader(textReader) : XmlReader.Create(textReader))
return GetObjectFromXml<T>(xmlReader, localName, namespaceURI);
}
public static T GetObjectFromXml<T>(XmlReader reader, string localName, string namespaceURI)
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "IWantThis" && reader.NamespaceURI == namespaceURI)
{
var serializer = XmlSerializerFactory.Create(typeof(T), localName, namespaceURI);
using (var subReader = reader.ReadSubtree())
return (T)serializer.Deserialize(subReader);
}
}
// Or throw an exception?
return default(T);
}
}
// This class copied from this answer https://stackoverflow.com/a/873281/3744182
// To https://stackoverflow.com/questions/870293/can-i-make-xmlserializer-ignore-the-namespace-on-deserialization
// By https://stackoverflow.com/users/48082/cheeso
// helper class to ignore namespaces when de-serializing
public class NamespaceIgnorantXmlTextReader : XmlTextReader
{
public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader): base(reader) { }
public override string NamespaceURI { get { return ""; } }
}
public static class XmlSerializerFactory
{
// To avoid a memory leak the serializer must be cached.
// https://stackoverflow.com/questions/23897145/memory-leak-using-streamreader-and-xmlserializer
// This factory taken from
// https://stackoverflow.com/questions/34128757/wrap-properties-with-cdata-section-xml-serialization-c-sharp/34138648#34138648
readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache;
readonly static object padlock;
static XmlSerializerFactory()
{
padlock = new object();
cache = new Dictionary<Tuple<Type, string, string>, XmlSerializer>();
}
public static XmlSerializer Create(Type serializedType, string rootName, string rootNamespace)
{
if (serializedType == null)
throw new ArgumentNullException();
if (rootName == null && rootNamespace == null)
return new XmlSerializer(serializedType);
lock (padlock)
{
XmlSerializer serializer;
var key = Tuple.Create(serializedType, rootName, rootNamespace);
if (!cache.TryGetValue(key, out serializer))
{
cache[key] = serializer = new XmlSerializer(serializedType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
}
return serializer;
}
}
}
演示小提琴here.