web-dev-qa-db-ja.com

問題-XML宣言はドキュメントの先頭でのみ許可されます

xml:19558:パーサーエラー:XML宣言はドキュメントの先頭でのみ許可されます

解決策はありますか? php XMLReaderを使用して大きなXMLファイルを解析していますが、このエラーが発生します。ファイルが適切にフォーマットされていないことは知っていますが、ファイルを調べてこれらの余分な宣言を削除することは不可能だと思います。だからどんなアイデアでも、助けてください

8
Aamir

最初のタグの前に空白がないことを確認してください。これを試して:

    <?php
//Declarations
$file = "data.txt"; //The file to read from.

#Read the file
$fp = fopen($file, "r"); //Open the file
$data = ""; //Initialize variable to contain the file's content
while(!feof($fp)) //Loop through the file, read it till the end.
{
    $data .= fgets($fp, 1024); //append next kb to data
} 
fclose($fp); //Close file
#End read file
$split = preg_split('/(?<=<\/xml>)(?!$)/', $data); //Split each xml occurence into its own string

foreach ($split as $sxml) //Loop through each xml string
{
    //echo $sxml;
    $reader = new XMLReader(); //Initialize the reader
    $reader->xml($sxml) or die("File not found"); //open the current xml string
    while($reader->read()) //Read it
    {
        switch($reader->nodeType)
        {
            case constant('XMLREADER::ELEMENT'): //Read element
                if ($reader->name == 'record')
                {
                    $dataa = $reader->readInnerXml(); //get contents for <record> tag.
                    echo $dataa; //Print it to screen.
                }
            break;
        }
    }
    $reader->close(); //close reader
}
?>

$ file変数を必要なファイルに設定します。これが4GBのファイルでどれだけうまく機能するかはわかりません。そうでない場合は教えてください。

編集:これは別の解決策です、それはより大きなファイルでよりうまくいくはずです(それがファイルを読んでいるときに解析します)。

<?php
set_time_limit(0);
//Declarations
$file = "data.txt"; //The file to read from.

#Read the file
$fp = fopen($file, "r") or die("Couldn't Open"); //Open the file

$FoundXmlTagStep = 0;
$FoundEndXMLTagStep = 0;
$curXML = "";
$firstXMLTagRead = false;
while(!feof($fp)) //Loop through the file, read it till the end.
{
    $data = fgets($fp, 2);
    if ($FoundXmlTagStep==0 && $data == "<")
        $FoundXmlTagStep=1;
    else if ($FoundXmlTagStep==1 && $data == "x")
        $FoundXmlTagStep=2;
    else if ($FoundXmlTagStep==2 && $data == "m")
        $FoundXmlTagStep=3;
    else if ($FoundXmlTagStep==3 && $data == "l")
    {
        $FoundXmlTagStep=4;
        $firstXMLTagRead = true;
    }
    else if ($FoundXmlTagStep!=4)
        $FoundXmlTagStep=0;

    if ($FoundXmlTagStep==4)
    {
        if ($firstXMLTagRead)
        {
            $firstXMLTagRead = false;
            $curXML = "<xm";
        }
        $curXML .= $data;

        //Start trying to match end of xml
        if ($FoundEndXMLTagStep==0 && $data == "<")
            $FoundEndXMLTagStep=1;
        elseif ($FoundEndXMLTagStep==1 && $data == "/")
            $FoundEndXMLTagStep=2;
        elseif ($FoundEndXMLTagStep==2 && $data == "x")
            $FoundEndXMLTagStep=3;
        elseif ($FoundEndXMLTagStep==3 && $data == "m")
            $FoundEndXMLTagStep=4;
        elseif ($FoundEndXMLTagStep==4 && $data == "l")
            $FoundEndXMLTagStep=5;
        elseif ($FoundEndXMLTagStep==5 && $data == ">")
        {
            $FoundEndXMLTagStep=0;
            $FoundXmlTagStep=0;
            #finished Reading XML
            ParseXML ($curXML);
        }
        elseif ($FoundEndXMLTagStep!=5)
            $FoundEndXMLTagStep=0;
    }
} 
fclose($fp); //Close file
function ParseXML ($xml)
{
    //echo $sxml;
    $reader = new XMLReader(); //Initialize the reader
    $reader->xml($xml) or die("File not found"); //open the current xml string
    while($reader->read()) //Read it
    {
        switch($reader->nodeType)
        {
            case constant('XMLREADER::ELEMENT'): //Read element
                if ($reader->name == 'record')
                {
                    $dataa = $reader->readInnerXml(); //get contents for <record> tag.
                    echo $dataa; //Print it to screen.
                }
            break;
        }
    }
    $reader->close(); //close reader
}
?>
24
Ben

この問題のもう1つの考えられる原因は、Unicodeファイルヘッドです。 XMLのエンコーディングがUTF-8の場合、ファイルの内容は常にこれらの3バイトの「EFBBBF」で始まります。バイト配列から文字列に変換しようとすると、これらのバイトが誤って解釈される可能性があります。解決策は、バイト配列からgetStringを読み取らずに、バイト配列をファイルに直接書き込むことです。

ASCIIにはファイルヘッドがありませんUnicode:FF FE UTF-8:EF BB BF UTF-32:FF FE 00 00

Ultraeditでファイルを開くだけで、これらのバイトを確認できます。

1
kaven

複数のXML宣言がある場合は、多くのXMLファイルと、複数のルート要素が連結されている可能性があります。それらをどのように意味のある形で解析するかは明確ではありません。

最初に実際のXMLを提供するために、XMLのソースを取得するように一生懸命努力してください。それが機能しない場合は、XMLを解析する前に、XMLを修正するための前処理を実行できるかどうかを確認してください。

1
Ned Batchelder