2017-07-09 10 views
3

スキーマのオフラインでXMLファイルを検証する方法を理解する必要があります。 2,3日を見回した後、基本的にはスキーマの内部参照が必要でした。私はそれらを見つけてダウンロードし、ローカルシステムパスへの参照を変更する必要がありました。私が見つけられなかったのは、正確にそれを行う方法でした。参照を外部ではなく内部的に変更するために、どこでどのように参照を変更できますか?スキーマをダウンロードする最善の方法は何ですか?オフラインでのJavaによるXML検証

答えて

0

これを行うには3通りの方法があります。スキル・ドキュメントのローカル・コピーが必要であるという共通点があります。私は、インスタンス文書が現在xsi:schemaLocationおよび/またはxsi:noNamespaceSchemaLocationを使用して、Web上のスキーマ文書を保持する場所を指すことを前提としています。

(a)インスタンス文書を変更して、スキーマ文書のローカルコピーを参照します。これは通常不便です。

(b)リモートファイルの要求がローカルファイルにリダイレクトされるように参照をリダイレクトします。これを設定する方法は、使用しているスキーマバリデータとその呼び出し方法によって異なります。

(c)スキーマプロセッサに、xsi:schemaLocationおよびxsi:noNamespaceSchemaLocationの値を無視し、スキーマプロセッサの呼び出しAPIを使用して指定したスキーマに対して検証するよう伝えます。ここでも、詳細は使用しているスキーマプロセッサによって異なります。

(c):ソースドキュメントを検証するときに、定義によって完全に信頼できないため、正しいxsi:schemaLocation属性が含まれていると信じるのはなぜですか?

0

XmlValidateは、ターゲットスキーマに対して1つまたは複数のXMLファイルをオフラインで検証できるシンプルで強力なコマンドラインツールです。ローカルxmlファイルをファイル名、ディレクトリ、またはURLでスキャンできます。

XmlValidateはスキーマ名前空間とローカルファイルにマッピングする設定ファイルに基づいてschemaLocationを自動的に追加します。このツールは、設定ファイルで参照されているXMLスキーマに対して検証します。

http://www.opengis.net/kml/2.2=${XV_HOME}/schemas/kml22.xsd 
http://appengine.google.com/ns/1.0=C:/xml/appengine-web.xsd 
urn:oasis:names:tc:ciq:xsdschema:xAL:2.0=C:/xml/xAL.xsd 

注上記$ {XV_HOME}トークンは単にXMLVALIDATEから実行されている最上位のディレクトリの別名であること:ここ

は、設定ファイル内のスキーマを対象とする名前空間の一例のマッピングです。場所も同様に完全なファイルパスにすることができます。

XmlValidateは、Java Runtime Environment (JRE)で動作するオープンソースプロジェクト(ソースコード利用可能)です。バンドルされたアプリケーション(Javaジャー、サンプルなど)はhereからダウンロードできます。

複数のXMLファイルに対してXmlValidateをバッチモードで実行すると、検証結果の概要が表示されます。

Errors: 17 Warnings: 0 Files: 11 Time: 1506 ms 
Valid files 8/11 (73%) 
0

LSInput.getCharacterStream()の の呼び出しはローカルパスからスキーマを提供するように、あなたはSchemaFactoryResourceResolverLSInputの独自の実装を設定することができます。

オフライン検証を行うために余分なクラスを作成しました。

new XmlSchemaValidator().validate(xmlStream, schemaStream, "https://schema.datacite.org/meta/kernel-4.1/", 
         "schemas/datacite/kernel-4.1/"); 

2つのInputStreamが渡されます。 1つはxml用、もう1つはスキーマ用です。 baseUrlとlocalPath(クラスパス上の相対パス)が3番目と4番目のパラメータとして渡されます。最後の2つのパラメータは、バリデータによってローカルパスまたは追加されたスキーマをローカルで検索するために使用されます。

https://schema.datacite.org/meta/kernel-4.1/から一連のスキーマと例を使用してテストしました。

完全な例:

@Test 
public void validate4() throws Exception { 
     InputStream xmlStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(
         "schemas/datacite/kernel-4.1/example/datacite-example-complicated-v4.1.xml"); 
     InputStream schemaStream = Thread.currentThread().getContextClassLoader() 
         .getResourceAsStream("schemas/datacite/kernel-4.1/metadata.xsd"); 
     new XmlSchemaValidator().validate(xmlStream, schemaStream, "https://schema.datacite.org/meta/kernel-4.1/", 
         "schemas/datacite/kernel-4.1/"); 
} 

XmlSchemaValidatorがスキーマに対してXMLを検証し、含まれるスキーマのためにローカルに検索します。 ResourceResolverを使用して標準動作をオーバーライドし、ローカルで検索します。

public class XmlSchemaValidator { 
    /** 
    * @param xmlStream 
    *   xml data as a stream 
    * @param schemaStream 
    *   schema as a stream 
    * @param baseUri 
    *   to search for relative pathes on the web 
    * @param localPath 
    *   to search for schemas on a local directory 
    * @throws SAXException 
    *    if validation fails 
    * @throws IOException 
    *    not further specified 
    */ 
    public void validate(InputStream xmlStream, InputStream schemaStream, String baseUri, String localPath) 
        throws SAXException, IOException { 
     Source xmlFile = new StreamSource(xmlStream); 
     SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
     factory.setResourceResolver((type, namespaceURI, publicId, systemId, baseURI) -> { 
      LSInput input = new DOMInputImpl(); 
      input.setPublicId(publicId); 
      input.setSystemId(systemId); 
      input.setBaseURI(baseUri); 
      input.setCharacterStream(new InputStreamReader(
          getSchemaAsStream(input.getSystemId(), input.getBaseURI(), localPath))); 
      return input; 
     }); 
     Schema schema = factory.newSchema(new StreamSource(schemaStream)); 
     javax.xml.validation.Validator validator = schema.newValidator(); 
     validator.validate(xmlFile); 
    } 

    private InputStream getSchemaAsStream(String systemId, String baseUri, String localPath) { 
     InputStream in = getSchemaFromClasspath(systemId, localPath); 
     // You could just return in; , if you are sure that everything is on 
     // your machine. Here I call getSchemaFromWeb as last resort. 
     return in == null ? getSchemaFromWeb(baseUri, systemId) : in; 
    } 

    private InputStream getSchemaFromClasspath(String systemId, String localPath) { 
     System.out.println("Try to get stuff from localdir: " + localPath + systemId); 
     return Thread.currentThread().getContextClassLoader().getResourceAsStream(localPath + systemId); 
    } 

    /* 
    * You can leave out the webstuff if you are sure that everything is 
    * available on your machine 
    */ 
    private InputStream getSchemaFromWeb(String baseUri, String systemId) { 
     try { 
      URI uri = new URI(systemId); 
      if (uri.isAbsolute()) { 
       System.out.println("Get stuff from web: " + systemId); 
       return urlToInputStream(uri.toURL(), "text/xml"); 
      } 
      System.out.println("Get stuff from web: Host: " + baseUri + " Path: " + systemId); 
      return getSchemaRelativeToBaseUri(baseUri, systemId); 
     } catch (Exception e) { 
      // maybe the systemId is not a valid URI or 
      // the web has nothing to offer under this address 
     } 
     return null; 
    } 

    private InputStream urlToInputStream(URL url, String accept) { 
     HttpURLConnection con = null; 
     InputStream inputStream = null; 
     try { 
      con = (HttpURLConnection) url.openConnection(); 
      con.setConnectTimeout(15000); 
      con.setRequestProperty("User-Agent", "Name of my application."); 
      con.setReadTimeout(15000); 
      con.setRequestProperty("Accept", accept); 
      con.connect(); 
      int responseCode = con.getResponseCode(); 
      if (responseCode == HttpURLConnection.HTTP_MOVED_PERM 
          || responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == 307 
          || responseCode == 303) { 
       String redirectUrl = con.getHeaderField("Location"); 
       try { 
        URL newUrl = new URL(redirectUrl); 
        return urlToInputStream(newUrl, accept); 
       } catch (MalformedURLException e) { 
        URL newUrl = new URL(url.getProtocol() + "://" + url.getHost() + redirectUrl); 
        return urlToInputStream(newUrl, accept); 
       } 
      } 
      inputStream = con.getInputStream(); 
      return inputStream; 
     } catch (SocketTimeoutException e) { 
      throw new RuntimeException(e); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 

    } 

    private InputStream getSchemaRelativeToBaseUri(String baseUri, String systemId) { 
     try { 
      URL url = new URL(baseUri + systemId); 
      return urlToInputStream(url, "text/xml"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      throw new RuntimeException(e); 
     } 
    } 
} 

プリント

Try to get stuff from localdir: schemas/datacite/kernel-4.1/http://www.w3.org/2009/01/xml.xsd 
Get stuff from web: http://www.w3.org/2009/01/xml.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-titleType-v4.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-contributorType-v4.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-dateType-v4.1.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-resourceType-v4.1.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-relationType-v4.1.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-relatedIdentifierType-v4.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-funderIdentifierType-v4.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-descriptionType-v4.xsd 
Try to get stuff from localdir: schemas/datacite/kernel-4.1/include/datacite-nameType-v4.1.xsd 
+0

あなたもhttp://www.w3.org/2009/01/xml.xsd](http://www.w3.org/ [取得したい場合2009/01/xml.xsd)を、[LSInputインターフェースのpublicIdパラメーター](https://docs.oracle.com/javase/7/docs/api/org/w3c/dom/ls)で使用できるローカル・パスから削除します/LSInput.html#getPublicId())を使用して、URLをlocalPathesに関連付けるルックアップ構造を照会します。 – jschnasse