2

私はXMLファイルの解析に比較的慣れておらず、XMLReaderを使用して大きなXMLファイルを読み取ろうとしています。

<?xml version="1.0" encoding="UTF-8"?>
<ShowVehicleRemarketing environment="Production" lang="en-CA" release="8.1-Lite" xsi:schemaLocation="http://www.starstandards.org/STAR /STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd">
  <ApplicationArea>
    <Sender>
      <Component>Component</Component>
      <Task>Task</Task>
      <ReferenceId>w5/cron</ReferenceId>
      <CreatorNameCode>CreatorNameCode</CreatorNameCode>
      <SenderNameCode>SenderNameCode</SenderNameCode>
      <SenderURI>http://www.example.com</SenderURI>
      <Language>en-CA</Language>
      <ServiceId>ServiceId</ServiceId>
    </Sender>
    <CreationDateTime>CreationDateTime</CreationDateTime>
    <Destination>
      <DestinationNameCode>example</DestinationNameCode>
    </Destination>
  </ApplicationArea>
...

次のエラーが表示されます

ErrorException [警告]:XMLReader :: read()[xmlreader.read]:compress.zlib:// D:/WebDev/example/local/public/../upload/example.xml.gz:2:名前空間エラー: ShowVehicleRemarketingのschemaLocationの名前空間プレフィックスxsiが定義されていません

私は周りを検索しましたが、XMLReaderを使用して名前空間を持つXMLファイルを読み取るための有用な情報を見つけることができません-名前空間を定義する方法が実際に必要な場合はどうすればよいですか?関連するリソースへのリンク?

4

4 に答える 4

5

xsi名前空間の定義が必要です。例えば

<ShowVehicleRemarketing
  environment="Production"
  lang="en-CA"
  release="8.1-Lite"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.starstandards.org/STAR/STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd"
>

更新:ユーザー定義のフィルターを作成してから、XMLReaderにそのフィルターを使用させることができます。

stream_filter_register('darn', 'DarnFilter');
$src = 'php://filter/read=darn/resource=compress.zlib://something.xml.gz';
$reader->open($src);

次に、compress.zlibラッパーによって読み取られたコンテンツは、xmlns:xsi宣言を挿入できる(最初の)場所を見つける必要があるDarnFilterを介して「ルーティング」されます。しかし、これは非常に面倒であり、正しく実行するにはある程度の余裕があります(たとえば、理論的にはバケットAにはxs、バケットBi:schemとバケットCが含まれる可能性がありますaLocation=") 。


更新2:これは、xsi名前空間宣言を挿入するphpのフィルターのアドホックな例です。ほとんどテストされておらず(私が実行した1つのテストで動作しました;-))、文書化されていません。プロダクションコードではなく、概念実証として使用してください。

<?php
stream_filter_register('darn', 'DarnFilter');
$src = 'php://filter/read=darn/resource=compress.zlib://d:/test.xml.gz';

$r = new XMLReader;
$r->open($src);
while($r->read()) {
  echo '.';
}

class DarnFilter extends php_user_filter {
  protected $buffer='';
  protected $status = PSFS_FEED_ME;

  public function filter($in, $out, &$consumed, $closing)
  {
    while ( $bucket = stream_bucket_make_writeable($in) ) {
      $consumed += $bucket->datalen;
      if ( PSFS_PASS_ON == $this->status ) {
        // we're already done, just copy the content
        stream_bucket_append($out, $bucket);
      }
      else {
        $this->buffer .= $bucket->data;
        if ( $this->foo() ) {
          // first element found
          // send the current buffer          
          $bucket->data = $this->buffer;
          $bucket->datalen = strlen($bucket->data);
          stream_bucket_append($out, $bucket);
          $this->buffer = null;
          // no need for further processing
          $this->status = PSFS_PASS_ON;
        }
      }
    }
    return $this->status;
  }

  /* looks for the first (root) element in $this->buffer
  *  if it doesn't contain a xsi namespace decl inserts it
  */
  protected function foo() {
    $rc = false;
    if ( preg_match('!<([^?>\s]+)\s?([^>]*)>!', $this->buffer, $m, PREG_OFFSET_CAPTURE) ) {
      $rc = true;
      if ( false===strpos($m[2][0], 'xmlns:xsi') ) {
        echo ' inserting xsi decl ';
        $in = '<'.$m[1][0]
          . ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
          . $m[2][0] . '>';    
        $this->buffer = substr($this->buffer, 0, $m[0][1])
          . $in
          . substr($this->buffer, $m[0][1] + strlen($m[0][0]));
      }
    }
    return $rc;
  }
}

更新3:そしてこれがC#で書かれたアドホックソリューションです

XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
// prime the XMLReader with the xsi namespace
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");

using ( XmlReader reader = XmlTextReader.Create(
  new GZipStream(new FileStream(@"\test.xml.gz", FileMode.Open, FileAccess.Read), CompressionMode.Decompress),
  new XmlReaderSettings(),
  new XmlParserContext(null, nsmgr, null, XmlSpace.None)
)) {
  while (reader.Read())
  {
    System.Console.Write('.');
  }
}
于 2010-08-24T08:40:43.213 に答える
1

に渡す前に XML を取得file_get_contentsできます。str_replaceXMLReader

xsi プレフィックスに必要な名前空間宣言を挿入します。

$reader = new XMLReader;
$reader->xml(str_replace(
    '<ShowVehicleRemarketing',
    '<ShowVehicleRemarketing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"',
    file_get_contents('http://example.com/data.xml')));

別のオプションは、schemaLocation属性を削除することです。

$reader->xml(str_replace(
    'xsi:schemaLocation="http://www.starstandards.org/STAR /STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd"',
    '',
    file_get_contents('http://example.com/data.xml')));

ただし、ドキュメントにさらに多くのプレフィックスがある場合は、それらすべてを置き換える必要があります。

于 2010-08-24T09:28:10.677 に答える
1

不正な形式の XML を書き出しているものを修正するか、後で修正を実行する別のツールを作成してください。(必ずしもすべてを同時にメモリに読み込む必要はありません。おそらく、一度に 1 行ずつ読み書きして、データの入出力をストリーミングします。)

そうすれば、読み取りコードは、データに対して何か有用なことをしようと試み、同時にそれ修正することを心配する必要がありません。

于 2010-08-24T10:28:19.247 に答える
1

名前xsi空間は通常、スキーマ インスタンスの名前空間で使用するために予約されています。

xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'

そうでない場合、XML ファイルは XML+NS に準拠しておらず、解析できません。したがって、ソースドキュメントでそれを解決する必要があります。

xsi に関する注意: これは、検証パーサーを XML のスキーマの正しいスキーマの場所に誘導するため、考えられる他の名前空間よりもさらに重要です。

于 2010-08-24T10:33:14.413 に答える