user271807 から受け入れられた回答は素晴らしい解決策ですが、次のような内部例外で例外を回避するために、フラグメントの xml ルートも設定する必要があることがわかりました。
...xmlns=''> was not expected
この例外は、この xml ドキュメントの内部の Authentication 要素のみを逆シリアル化しようとしたときに発生しました。
<?xml version=""1.0"" encoding=""UTF-8""?>
<Api>
<Authentication>
<sessionid>xxx</sessionid>
<errormessage>xxx</errormessage>
</Authentication>
</ApI>
したがって、この拡張メソッドを再利用可能なソリューションとして作成することになりました-警告にはメモリリークが含まれています。以下を参照してください。
public static T DeserializeXml<T>(this string @this, string innerStartTag = null)
{
using (var stringReader = new StringReader(@this))
using (var xmlReader = XmlReader.Create(stringReader)) {
if (innerStartTag != null) {
xmlReader.ReadToDescendant(innerStartTag);
var xmlSerializer = new XmlSerializer(typeof(T), new XmlRootAttribute(innerStartTag));
return (T)xmlSerializer.Deserialize(xmlReader.ReadSubtree());
}
return (T)new XmlSerializer(typeof(T)).Deserialize(xmlReader);
}
}
2017 年 3 月 20 日更新: 以下のコメントが指摘しているように、XmlSerializer のコンストラクターの 1 つを使用するとメモリ リークの問題が発生するため、以下に示すようにキャッシュ ソリューションを使用することになりました。
/// <summary>
/// Deserialize XML string, optionally only an inner fragment of the XML, as specified by the innerStartTag parameter.
/// </summary>
public static T DeserializeXml<T>(this string @this, string innerStartTag = null) {
using (var stringReader = new StringReader(@this)) {
using (var xmlReader = XmlReader.Create(stringReader)) {
if (innerStartTag != null) {
xmlReader.ReadToDescendant(innerStartTag);
var xmlSerializer = CachingXmlSerializerFactory.Create(typeof (T), new XmlRootAttribute(innerStartTag));
return (T) xmlSerializer.Deserialize(xmlReader.ReadSubtree());
}
return (T) CachingXmlSerializerFactory.Create(typeof (T), new XmlRootAttribute("AutochartistAPI")).Deserialize(xmlReader);
}
}
}
/// <summary>
/// A caching factory to avoid memory leaks in the XmlSerializer class.
/// See http://dotnetcodebox.blogspot.dk/2013/01/xmlserializer-class-may-result-in.html
/// </summary>
public static class CachingXmlSerializerFactory {
private static readonly ConcurrentDictionary<string, XmlSerializer> Cache = new ConcurrentDictionary<string, XmlSerializer>();
public static XmlSerializer Create(Type type, XmlRootAttribute root) {
if (type == null) {
throw new ArgumentNullException(nameof(type));
}
if (root == null) {
throw new ArgumentNullException(nameof(root));
}
var key = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", type, root.ElementName);
return Cache.GetOrAdd(key, _ => new XmlSerializer(type, root));
}
public static XmlSerializer Create<T>(XmlRootAttribute root) {
return Create(typeof (T), root);
}
public static XmlSerializer Create<T>() {
return Create(typeof (T));
}
public static XmlSerializer Create<T>(string defaultNamespace) {
return Create(typeof (T), defaultNamespace);
}
public static XmlSerializer Create(Type type) {
return new XmlSerializer(type);
}
public static XmlSerializer Create(Type type, string defaultNamespace) {
return new XmlSerializer(type, defaultNamespace);
}
}