3

名前空間を使用して、XMLに格納されているオブジェクトの逆シリアル化を支援するアプリケーションがあります。XML名前空間は、オブジェクトが存在するC#名前空間でもあります。たとえば、次のXMLスニップがあるとします。

<xml-config xmlns:app="MyAppNS">
  <app:Person>
    <Name>Bill</Name>
    <Car>
      <Make>Honda</Make>
      <Model>Accord</Model>
    </Car>
  </app:Person>

  <app:Person>
    <Name>Jane</Name>
    <Car>
      <Make>VW</Make>
      <Model>Jetta</Model>
    </Car>
  </app:Person>

  <app:Car>
    <Make>Audi</Make>
    <Model>A6</Model>
  </app:Car>
</xml-config>

構成は、実際には単なるオブジェクトのランダムなバッグです。ご覧のとおり、トップレベルにはPersonとオブジェクトが混在しています。Car名前空間を使用して、適切な逆シリアル化のためにロード時にオブジェクトタイプを決定します。ドキュメントをロードするためのコードは次のとおりです。

public static void LoadFile(String file) {
    XmlDocument doc = new XmlDocument();
    doc.Load(file);

    XmlNode root = doc.DocumentElement;
    foreach (XmlNode child in root.ChildNodes) {
        if (child.NodeType != XmlNodeType.Element) {
            continue;
        }

        Object obj = LoadObject(child);
        // TODO handle object here...
    }
}

private static Object LoadObject(XmlNode node) {
    Object obj = null;

    StringBuilder str = new StringBuilder();
    if ((node.Prefix != null) && (node.Prefix != "")) {
        str.Append(node.NamespaceURI).Append('.');
    }
    str.Append(node.LocalName);

    Assembly assy = Assembly.GetExecutingAssembly();
    Type type = assy.GetType(str.ToString());
    XmlSerializer serdes = new XmlSerializer(type);

    using (XmlNodeReader reader = new XmlNodeReader(node)) {
        obj = serdes.Deserialize(reader);
    }

    return obj;
}

多くの人がすぐに問題を認識しますが、このコードを使用すると、結果のPersonオブジェクトは空になりますが、エラーは発生しません。デシリアライザーに子要素を設定する唯一の方法は、子要素に同じ名前空間を使用することです。

  <app:Person>
    <app:Name>Bill</app:Name>
    <app:Car>
      <app:Make>Honda</app:Make>
      <app:Model>Accord</app:Model>
    </app:Car>
  </app:Person>

私が試した他の唯一のオプションは、要素名として完全修飾型名を使用することです(名前空間なし)が、それはうまくいきませんでした。デシリアライザーにXMLノードのプレフィックスなしの子を受け入れさせる方法はありますか?

4

1 に答える 1

0

私はついにこれを達成する方法を見つけ、ここにある答えを修正しました。

開始ノードの名前空間を複製するカスタムデシリアライザーを作成しました。

public class CustomXmlNodeReader : XmlNodeReader {

    private String _namespace;

    public CustomXmlNodeReader(XmlNode node) : base(node) {
        _namespace = node.NamespaceURI;
    }

    public override String NamespaceURI {
        get { return _namespace; }
    }
}

このリーダーを使用して、次のように保存されたオブジェクトをロードできます。

using (XmlNodeReader reader = new CustomXmlNodeReader(node)) {
    obj = serdes.Deserialize(reader);
}

これはXML(特定の名前空間の適用を強制する)には少し悪い形式であることを私は知っていますが、それは私のニーズに非常によく合っています。それが他の誰かを助ける場合に備えて、ここで答えました。

于 2012-11-24T04:12:39.933 に答える