15

バックグラウンド:

私たちは、顧客が定義済みの (つまり、私たちが管理していない) XML 形式でデータを提供できるようにするアプリケーションを構築しています。XSD はサード パーティから提供されており、処理前にスキーマ検証に合格した XML ファイルを受け取る予定です。

問題:

提供された XSD には、デフォルトのターゲット名前空間が含まれています。つまり、顧客が名前空間を含まない XML ファイルを提供した場合、検証はパスします。私たちは明らかに、彼らが合格するがすべきではないというものを提供することを望んでいませんが、より大きな懸念は、解決策が見つからない場合に各要素に対して実行する必要がある大量の追加チェックに関するものです。 XML 検証。

質問:

.NET に検証を実行させ、提供された XML および XSD の名前空間を無視させることは可能ですか? つまり、何らかの方法で、名前空間が関連付けられていると「仮定」します。

  1. メモリ内の名前空間を簡単かつ確実に削除することは可能ですか?
  2. これらの状況でのベストプラクティスは何ですか?

私がこれまでに持っている解決策:

  1. 更新されるたびに、XSD から名前空間を削除します (あまり頻繁に行うべきではありません。これは、名前空間を提供した場合でも検証に合格するという事実を回避するものではありません。
  2. XSD から名前空間を削除し、毎回受信 XML から名前空間を削除する方法を見つけます。これは、単純なことを実行するための多くのコードのようです。
  3. 正しい名前空間を持つことを確認するために、XML ファイルを検証する前に事前修飾を行います。ファイルの内容が正しい場合、無効な名前空間のためにそれらを失敗させるのは間違っているようです。
  4. 名前空間を持たない複製 XSD を作成しますが、間違った名前空間または別の名前空間を提供するだけの場合は、合格します。

XML の例:

<?xml version="1.0"?>
<xsd:schema version='3.09' elementFormDefault='qualified' attributeFormDefault='unqualified' id='blah' targetNamespace='urn:schemas-blah.com:blahExample' xmlns='urn:blah:blahExample' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
...
</xsd:schema>

名前空間が異なる

 <?xml version="1.0" encoding="UTF-8" ?> 
<root xmlns="urn:myCompany.com:blahExample1" attr1="2001-03-03" attr2="google" >
...
</root>

名前空間がまったくない。

 <?xml version="1.0" encoding="UTF-8" ?> 
<root attr1="2001-03-03" attr2="google" >
...
</root>
4

2 に答える 2

6

同じ問題を解決しようとしています。私はかなりきれいな解決策だと思うものを思いつきました。わかりやすくするために、入力パラメーターの検証を省略しました。

まず、シナリオ: ファイルを受け取る Web サービスがあります。このファイルは、「整形式」の xml であり、XSD に対して有効である必要があります。もちろん、私たちは「適切な形式」を信頼していませんし、「私たちが知っている」ことが正しいという XSD に対して有効であることも信頼していません。

そのような webservice メソッドのコードを以下に示します。一目瞭然だと思います。

重要な点は、検証が行われる順序です。ロードする前に名前空間をチェックするのではなく、後でチェックしますが、きれいにチェックします。

ほとんどのファイルが「適切」であることが予想され、それがフレームワークの処理方法であるため (したがって、私はそれに抵抗しません)、いくつかの例外処理を行うことができると判断しました。

private DataTable xmlErrors;
[WebMethod]
public string Upload(byte[] f, string fileName) {
    string ret = "This will have the response";

    // this is the namespace that we want to use
    string xmlNs = "http://mydomain.com/ns/upload.xsd";

    // you could put a public url of xsd instead of a local file
    string xsdFileName = Server.MapPath("~") + "//" +"shiporder.xsd"; 

    // a simple table to store the eventual errors 
    // (more advanced ways possibly exist)
    xmlErrors = new DataTable("XmlErrors");
    xmlErrors.Columns.Add("Type");
    xmlErrors.Columns.Add("Message");

    try {
        XmlDocument doc = new XmlDocument(); // create a document

        // bind the document, namespace and xsd
        doc.Schemas.Add(xmlNs, xsdFileName); 

        // if we wanted to validate if the XSD has itself XML errors
        // doc.Schemas.ValidationEventHandler += 
        // new ValidationEventHandler(Schemas_ValidationEventHandler);

        // Declare the handler that will run on each error found
        ValidationEventHandler xmlValidator = 
            new ValidationEventHandler(Xml_ValidationEventHandler);

        // load the document 
        // will trhow XML.Exception if document is not "well formed"
        doc.Load(new MemoryStream(f));

        // Check if the required namespace is present
        if (doc.DocumentElement.NamespaceURI == xmlNs) {

            // Validate against xsd 
            // will call Xml_ValidationEventHandler on each error found
            doc.Validate(xmlValidator);

            if (xmlErrors.Rows.Count == 0) {
                ret = "OK";
            } else {
                // return the complete error list, this is just to proove it works
                ret = "File has " + xmlErrors.Rows.Count + " xml errors ";
                ret += "when validated against our XSD.";
            }
        } else {
            ret = "The xml document has incorrect or no namespace.";                
        }
    } catch (XmlException ex) {
        ret = "XML Exception: probably xml not well formed... ";
        ret += "Message = " + ex.Message.ToString();
    } catch (Exception ex) {
        ret = "Exception: probably not XML related... "
        ret += "Message = " + ex.Message.ToString();
    }
    return ret;
}

private void Xml_ValidationEventHandler(object sender, ValidationEventArgs e) {
    xmlErrors.Rows.Add(new object[] { e.Severity, e.Message });
}

さて、xsd には次のようなものがあります。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="shiporder"
    targetNamespace="http://mydomain.com/ns/upload.xsd"
    elementFormDefault="qualified"
    xmlns="http://mydomain.com/ns/upload.xsd"
    xmlns:mstns="http://mydomain.com/ns/upload.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
    <xs:simpleType name="stringtype">
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
    ...
    </xs:schema>

そして、「良い」XML は次のようになります。

<?xml version="1.0" encoding="utf-8" ?>
<shiporder orderid="889923"  xmlns="http://mydomain.com/ns/upload.xsd">
  <orderperson>John Smith</orderperson>
  <shipto>
    <names>Ola Nordmann</names>
    <address>Langgt 23</address>

「不適切な形式の XML」、「XSD による無効な入力」、「不適切な名前空間」をテストしました。

参照:

メモリストリームから読み取る

ウェルフォームの例外処理チェックを回避しようとしています

XSD に対する検証、エラーのキャッチ

インライン スキーマ検証に関する興味深い投稿


こんにちはマーティン、コメントセクションは私の答えには短すぎるので、ここでそれを与えます。それは完全な答えであるかもしれません。一緒に改善しましょう:)

次のテストを行いました。

  • テスト: xmlns="blaa"
  • 結果: 名前空間が間違っているため、ファイルは拒否されます。
  • テスト: xmlns="http://mydomain.com/ns/upload.xsd" および xmlns:a="blaa" で、要素に "a:someElement" が含まれている
  • 結果: ファイルは、「a:someElement」を想定していないというエラーを返します。
  • テスト: xmlns="http://mydomain.com/ns/upload.xsd" および xmlns:a="blaa" で、要素に「someElement」があり、必要な属性が欠落している
  • 結果: ファイルは、属性が欠落しているというエラーを返します

従った戦略(私が好む)は、ドキュメントが準拠していない場合は受け入れず、理由に関する情報を提供することでした(たとえば、「間違った名前空間」)。

この戦略は、あなたが以前に言ったことに反しているようです。

ただし、お客様が送信された XML で名前空間の宣言を見逃した場合でも、それを検証できることをお伝えしたいと思います。「失敗したから直せ!」と言いたいわけではありません。

この場合、XML で定義された名前空間を無視できるようです。そのためには、正しい名前空間の検証をスキップします。

    ...
    // Don't Check if the required namespace is present
    //if (doc.DocumentElement.NamespaceURI == xmlNs) {

        // Validate against xsd 
        // will call Xml_ValidationEventHandler on each error found
        doc.Validate(xmlValidator);

        if (xmlErrors.Rows.Count == 0) {
            ret = "OK - is valid against our XSD";
        } else {
            // return the complete error list, this is just to proove it works
            ret = "File has " + xmlErrors.Rows.Count + " xml errors ";
            ret += "when validated against our XSD.";
        }
    //} else {
    //    ret = "The xml document has incorrect or no namespace.";                
    //}
    ...


他のアイデア...

これと並行して、提供された名前空間を独自のものにdoc.DocumentElement.NamespaceURI = "mySpecialNamespace"置き換えるには、ルート要素の名前空間を置き換えるように設定できます。

参考

複数の名前空間をルート要素に追加

于 2012-06-14T16:23:42.073 に答える
0

XSD スキーマの背後にある要点は、型指定されていない XML を厳密に型指定された XML にすることです。

XML 型は、ノード名と名前空間の組み合わせとして定義できます。

誰かが名前空間なしで XML を送信した場合、その意図にもかかわらず、XML は XSD スキーマで定義された型を参照しません。

XML 検証の観点からは、XML は有効である限り有効です。

  1. それはよく形成されています
  2. xmlns 属性で指定されているように、型指定された XML 定義を確認します。
于 2012-01-04T13:55:41.767 に答える