2011-01-14 19 views
2

実際に定義されている "定義されていない"名前空間接頭辞を使用してXMLを逆シリアル化するのに問題があります。"名前空間接頭辞が定義されていません"実際に定義されています

さまざまなクライアントに対応する内部WebサービスをC#で公開しました。新しいクライアントのIDEは、XML出力のすべての要素に対してxsi:typeを宣言し、この「機能」をオフにすることはできません。

彼らが作り出すXMLメッセージは、このようになります。ここで、「名前空間」は正しい名前空間です。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<soapenv:Body> 
    <myOperation xsi:type="ns1:namespace" xmlns="namespace" xmlns:ns1="namespace"> 
    <inputString xsi:type="xsd:string">ABCDEF</inputString> 
    <books xsi:type="ns1:booksType"> 
     <bookID xsi:type="xsd:string">ABC123</bookID> 
     <bookID xsi:type="xsd:string">DEF456</bookID> 
    </books> 
    <!-- ... snip... --> 
    </myOperation> 
</soapenv:Body> 

<books>は基本的に文字列の配列です。

サービスメソッドはXmlNodeとして受け入れますが、XmlSerializerは "prefix 'ns1' not defined"エラーをスローします。 (それは親ノードで定義されていますが、それは十分ではないようです。)wsdl.exeを使用してクラスを生成し、入力を逆シリアル化する同様の問題があります。

XmlNamespaceManagerを使用してプレフィックスを指定すると、マジックナンバーに似ていないようですが、特定のコンシューマがどのプレフィックスを宣言するかは予測できません。属性を取り除かずにこれを処理する方法はありますか(books.Attributes.RemoveAll)?特にエレガントな感じはしません。

books.OuterXMLには、その接頭辞()を使用するためにインバウンドの要素をハックしないと 'なぜns1'の情報が含まれていないのか分かりませんが、 'ns1'は上記の前の定義から認識されません。

誰かが助けることができる、または少なくとも教育に感謝します。

編集:<books>にプレフィックス()を使用するように変更しても問題ありません。これは、xmlnsまたはnoを定義したかどうかに関係なく動作します。これはthis answerと一貫しているかもしれませんが、サービスコードの接頭辞をどうやって宣言するかはまだ分かりません。

@クリス、確かに。私は、「閉鎖された源を持つ刺青」と「助ける者に役立つ」とのバランスをとることができると願っています。ここで "books"は、serviceメソッドのパラメータで受け取ったXmlNodeです。 (トピックを下車しないようにするだけでなく、謙虚に、一般的には、それを改善するための提案を取るでしょう。私はまだ初心者です。)

XmlSerializer xmlSerializer = new XmlSerializer(typeof(booksType)); 
StringReader xmlDataReader = new StringReader(books.OuterXml); 
books = (booksType)xmlSerializer.Deserialize(xmlDataReader); 

クラスはかなりこのです:

[Serializable()] 
[XmlRoot("books", Namespace = "namespace")] 
[XmlTypeAttribute(TypeName = "booksType", Namespace = "namespace")] 
public class booksType 
{ 
    [XmlElement(ElementName = "bookID")] 
    public string[] bookIDs { get; set; } 
} 
+0

一部のDOM実装では、同じ名前空間URIが2回バインドされているとは見なされません。 xmlns = "namespace"を削除してもそれでも文句はありますか? – biziclop

+0

@biziclop - これは興味深い提案です。私が以前見たことのない問題です。どのDOM実装を見たことがありますか? –

+0

要素のプレフィックス()を使用すると、(xmlnsが定義された)動作します。 xmlnsを定義していない場合は、接頭辞を入れておく必要があります。私はbooks要素にプレフィックスを使用していたので、それはもっと重要です。 – wilee

答えて

2

あなたのデシリアライズコードは次のようになります:

XmlSerializer sz = new XmlSerializer(typeof(booksType)); 
    var reader = new XmlNodeReader(booksXmlNode); 
    var books = sz.Deserialize(reader); 

[EDIT] OuterXmlを経由してXML文字列に変換するナムを切り取るように見えるのに対し、名前空間宣言は、XmlNodeのに保存されているので、これは、優れていますns1接頭辞のespace宣言、シリアライザはこの接頭辞を含むtype属性値をbarfsします。私はこれがXML実装のバグだと思っていますが、XMLの得意先がこれを確認できるかもしれません。

これはあなたが見ているエラーよりも先に進むはずですが、問題が完全に解決しているかわかりません。

[詳細な編集]以下のコメントに記載されているように、.NET XmlSerializerには、デシリアライズが失敗するバグがあります。生成されたアセンブリに逆シリアル化コードをステップ、次の条件がテストされている点がある。

(object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_namespace)) 

XmlQualifiedNameNamespace性がid2_namespace可変文字列と同じ値(「名前空間」)を有しているが、文字列値等価性のテストではなく、オブジェクト識別テストとしてコード化されているため、条件はfalseと評価されます。この条件が満たされなければ、OPによって報告された例外に直接つながる。

このバグは、逆シリアル化されるオブジェクトのXMLがオブジェクトのルート要素名に1つの接頭辞を使用し、その要素のルート要素名に別の接頭辞(同じ名前空間として定義されている) xsi:type属性。

+0

返信ありがとうございます(遅れて申し訳ありません) - XmlNodeReaderを試しましたが、今のところ「指定された型が認識されませんでした:name = 'booksType'、namespace = 'namespace'」です。繰り返しますが、プレフィックスを削除すると、問題は消えます。 – wilee

+0

はい、私もそれを再現することができます。 XmlSerializerのバグであると思われます。シリアル化するために構築された型を認識しないと主張しています。 –

関連する問題