【问题标题】:How to fix Fatal error: Uncaught Error: Call to a member function children() on string如何修复致命错误:未捕获的错误:调用字符串上的成员函数 children()
【发布时间】:2023-03-15 07:18:01
【问题描述】:

当我尝试解析 xml 网页并将数据写入 mysql 数据库表时,我收到错误 Fatal error: Uncaught Error: Call to a member function children() on string

我尝试使用以下代码来做到这一点 任何人都可以建议我解析 xml 网页端点并将数据写入 mysql 数据库表的正确方法

<?php
function sanitize_for_xml($input) {
    // Convert input to UTF-8.
    $old_setting = ini_set('mbstring.substitute_character', '"none"');
    $input = mb_convert_encoding($input, 'UTF-8', 'auto');
    ini_set('mbstring.substitute_character', $old_setting);

    // Use fast preg_replace. If failure, use slower chr => int => chr conversion.
    $output = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', '', $input);
    if (is_null($output)) {
        // Convert to ints.
        // Convert ints back into a string.
        $output = ords_to_utfstring(utfstring_to_ords($input), TRUE);
    }
    return $output;

}
?>
<?php

                        $affectedRow = 0;
                        $url ="https://ngcareers.com/xmlfeed.xml";
                        $xml = simplexml_load_file($url) or die("Error: Cannot create object");
                        $xml = sanitize_for_xml($xml);
                        echo "xml is ".$xml;

                        $xml = str_replace("[^\\x20-\\x7e]", "",$xml);
                        $xml = str_replace("<b>", "",$xml);
                        $xml = str_replace("<u>", "",$xml);
                        $xml = str_replace("</u>", "",$xml);
                        $xml = str_replace("<providerUrl>", "",$xml);
                        $xml = str_replace("</providerUrl>", "",$xml);
                        $xml = str_replace("&lsquo;", "",$xml);
                        $xml = str_replace("&amp;", "",$xml);
                        $xml = str_replace("&rsquo;", "",$xml);
                        $xml = str_replace("&bull;", "",$xml);
                        $xml = str_replace("<strong>", "",$xml);
                        $xml = str_replace("</strong>", "",$xml);
                        $xml = str_replace("<p>", "",$xml);
                        $xml = str_replace("</p>", "",$xml);
                        $xml = str_replace("<br />", "",$xml);
                        $xml = str_replace("</b>", "",$xml);
                        $xml = str_replace("<li>", "",$xml);
                        $xml = str_replace("</li>", "",$xml);
                        $xml = str_replace("<ul>", "",$xml);

                        $xml = str_replace("</ul>", "",$xml);
                        $xml = str_replace("&#39;", "",$xml);
                        $xml = str_replace("&nbsp;", "",$xml);
                        $xml = str_replace("&quot;", "",$xml);
                        $xml = str_replace("<!--[endif]-->", "",$xml);
                        $xml = str_replace("<!--[if !supportLists]-->;", "",$xml);

                        foreach ($xml->children() as $row) {
                            $title = $row->title;
                            $link = $row->url;
                            $description = $row->description;
                            $date = $row->date;
                            $city = $row->city;
                            $state = $row->state;
                            $country = $row->country;
                            $company = $row->company;
                            $requirements= $row->requirements;
                            $category = $row->category;
                            $experience = $row->experience;
                            $salary = $row->salary;
                            $id = $row->id;

                            $sql = "INSERT INTO requirement(title,link,description,
                            jobdate,city,state,
                            country,company,requirements,
                            category,experience,salary,jobid) VALUES ('" . $title . "','" . $link . "','" . $description .
                                "','" . $date .  "','" . $city . "','" . $state . "','" . $country . "','" . $company . "','" .
                                $requirements . "','" . $category . "','" . $experience . "','" . $salary . "','" . $id
                                . "')";

                            $result = mysqli_query($con, $sql);

                            if (! empty($result)) {
                                $affectedRow ++;
                            } else {
                                $error_message = mysqli_error($con) . "\n";
                            }
                        }
                        ?>
                        <h2>Insert Job Data to  Table </h2>
                        <?php
                        if ($affectedRow > 0) {
                            $message = $affectedRow . " records inserted";
                        } else {
                            $message = "No records inserted";
                        }

                        ?>

【问题讨论】:

标签: php html xml


【解决方案1】:

您最好使用prepared statement 进行实际的数据库插入,IMO 使用标准的DOMDocument 结合DOMXPath 来查询XML 提要。以下内容仅用于处理 DOM,但尚未使用 db insert 进行测试

<?php
    /* utility to get item from XPath query relative to $obj */
    function nodevalue( $xp, $obj, $item ){
        return $xp->query($item,$obj)->item(0)->textContent ?: false;
    }


    $affectedRow = 0;
    $url='https://ngcareers.com/xmlfeed.xml';

    /* create DOMDodument - use our own error handling */
    libxml_use_internal_errors( true );
    $dom=new DOMDocument;
    $dom->validateOnParse=false;
    $dom->recover=true;
    $dom->load( $url );
    libxml_clear_errors();

    /* create the XPath object for queryng the DOM */
    $xp=new DOMXPath( $dom );

    /* Get a list of all jobs */
    $col=$xp->query( '//jobs/job' );




    if( $col->length > 0 ){
        /* create the basic SQL insert statement for use in a `prepared statement` */
        $sql='insert into `requirement`
            ( `title`, `link`, `description`, `jobdate`, `city`, `state`, `country`, `company`, `requirements`, `category`, `experience`, `salary`, `jobid` ) 
            values
            ( ?,?,?,?,?,?,?,?,?,?,?,?,? )';

        /* create the prepared statement */
        $stmt=$con->prepare( $sql );

        if( $stmt ){

            /* Bind the placeholders to variables */
            $stmt->bind_param('ssssssssssssi',
                        $title,
                        $link,
                        $description,
                        $date,
                        $city,
                        $state,
                        $country,
                        $company,
                        $requirements,
                        $category,
                        $experience,
                        $salary,
                        $id
                    );

            /* Iterate through all the jobs */
            foreach( $col as $job ){
                /* assign as variables each item from the job */
                $title=nodevalue( $xp, $job, 'title' );
                $link=nodevalue( $xp, $job, 'url' );
                $description=nodevalue( $xp, $job, 'description' );
                $date=nodevalue( $xp, $job, 'date' );
                $city=nodevalue( $xp, $job, 'city' );
                $state = nodevalue( $xp, $job, 'state' );
                $country = nodevalue( $xp, $job, 'country' );
                $company = nodevalue( $xp, $job, 'company' );
                $requirements= nodevalue( $xp, $job, 'requirements' );
                $category = nodevalue( $xp, $job, 'category' );
                $experience = nodevalue( $xp, $job, 'experience' );
                $salary = nodevalue( $xp, $job, 'salary' );
                $id = nodevalue( $xp, $job, 'id' );

                /* execute the INSERT statement */
                $status=$stmt->execute();

                if( $status )$affectedRow++;
            }


            echo $affectedRow==$col->length ? 'All records inserted' : sprintf('%d rows inserted',$affectedRow);

        }
    }
?>

更新的代码 - 愉快地插入 99/100 行

<?php

    /*
        Schema of table used to test below code

        +--------------+------------------+------+-----+---------+-------+
        | Field        | Type             | Null | Key | Default | Extra |
        +--------------+------------------+------+-----+---------+-------+
        | title        | varchar(128)     | YES  |     | NULL    |       |
        | link         | varchar(255)     | YES  |     | NULL    |       |
        | description  | text             | YES  |     | NULL    |       |
        | jobdate      | datetime         | YES  |     | NULL    |       |
        | city         | varchar(32)      | YES  |     | NULL    |       |
        | state        | varchar(32)      | YES  |     | NULL    |       |
        | country      | varchar(32)      | YES  |     | NULL    |       |
        | company      | varchar(64)      | YES  |     | NULL    |       |
        | requirements | text             | YES  |     | NULL    |       |
        | category     | varchar(128)     | YES  |     | NULL    |       |
        | experience   | text             | YES  |     | NULL    |       |
        | salary       | text             | YES  |     | NULL    |       |
        | jobid        | int(11) unsigned | NO   |     | NULL    |       |
        +--------------+------------------+------+-----+---------+-------+

    */


    /* utility to get item from XPath query relative to $obj */
    function nodevalue( $xp, $obj, $item ){
        return $xp->query($item,$obj)->item(0)->textContent ?: false;
    }

    $errors=array();
    $affectedRow = 0;
    $url='https://ngcareers.com/xmlfeed.xml';

    /* create DOMDodument - use our own error handling */
    libxml_use_internal_errors( true );
    $dom=new DOMDocument;
    $dom->validateOnParse=false;
    $dom->recover=true;
    $dom->load( $url );
    libxml_clear_errors();

    /* create the XPath object for queryng the DOM */
    $xp=new DOMXPath( $dom );

    /* Get a list of all jobs */
    $col=$xp->query( '//jobs/job' );




    if( $col->length > 0 ){

        /* create the basic SQL insert statement for use in a `prepared statement` */
        $sql='insert into `requirement`
            ( `title`, `link`, `description`, `jobdate`, `city`, `state`, `country`, `company`, `requirements`, `category`, `experience`, `salary`, `jobid` ) 
            values
            ( ?,?,?,?,?,?,?,?,?,?,?,?,? )';

        /* create the prepared statement */
        $stmt=$con->prepare( $sql );


        if( $stmt ){

            /* Bind the placeholders to variables */
            $stmt->bind_param('ssssssssssssi',
                        $title,
                        $link,
                        $description,
                        $date,
                        $city,
                        $state,
                        $country,
                        $company,
                        $requirements,
                        $category,
                        $experience,
                        $salary,
                        $id
                    );



            /* Iterate through all the jobs */
            foreach( $col as $index => $job ){
                /* assign as variables each item from the job */
                $title=nodevalue( $xp, $job, 'title' );
                $link=nodevalue( $xp, $job, 'url' );
                $description=htmlentities( nodevalue( $xp, $job, 'description' ) );
                $date=date( 'Y-m-d H:i:s', strtotime( nodevalue( $xp, $job, 'date' ) ) );
                $city=nodevalue( $xp, $job, 'city' );
                $state=nodevalue( $xp, $job, 'state' );
                $country=nodevalue( $xp, $job, 'country' );
                $company=nodevalue( $xp, $job, 'company' );
                $requirements=htmlentities( nodevalue( $xp, $job, 'requirements' ) );
                $category=nodevalue( $xp, $job, 'category' );
                $experience=nodevalue( $xp, $job, 'experience' );
                $salary=nodevalue( $xp, $job, 'salary' );
                $id=nodevalue( $xp, $job, 'id' );

                /* execute the INSERT statement */
                $status=$stmt->execute();

                if( $status )$affectedRow++;
                else $errors[]=array( 
                                'error'=>$stmt->error, 
                                'code'=>$stmt->errno, 
                                'index'=>$index, 
                                'title'=>$title,
                                'jobid'=>$id
                            );

            }



            echo $affectedRow==$col->length ? sprintf('All %d records inserted', $col->length ) : sprintf( 'inserted %d of %d rows', $affectedRow, $col->length );

            if( !empty( $errors ) ){
                printf('<pre><h2>Errors</h2>%s</pre>',print_r( $errors, true ) );
            }



        } else {
            echo "Failed to prepare SQL";
        }
    }
?>

【讨论】:

  • github.com/techlinesolutions/github/blob/master/code 查看 bove 存储库中的新代码。它仍然无法正常工作
  • 你有错误吗?检查 PHP 错误日志。代码是否进入循环 - 即:是否创建了准备好的语句?
  • 我认为存在逻辑错误。它不会进入循环并且错误日志中没有条目。请参阅此处的代码 github.com/techlinesolutions/github/blob/master/code
  • 这表明 SQL 语句有点不正确。仔细检查使用的名称,并可能使用if( $stmt){/* */} else { echo "error"; } 来识别是否是有罪的物品
  • 我在我的测试数据库中创建了一个模型表,其中显示了列名。最初它失败了,因为我将jobdate 列类型设置为datetime,但是传递了招聘广告中的原始格式化日期字符串。一旦转换为正确的格式,它就可以工作了。
【解决方案2】:

您在剥离 xml 标记后在 xml 上使用 children() 方法。这意味着,您的 xml 现在本质上是一个字符串。您只能在 xml 上使用 children()。

    $url ="https://ngcareers.com/xmlfeed.xml";
    $xml = simplexml_load_file($url);

    $data = [];

    foreach ($xml->children() as $key => $value) {
       if($value->getName() == 'jobs'){
          foreach ($value as  $jobValue) {
          $singleArr  =   [];
          foreach ($jobValue->children() as $childkey => $childValue) {
             $singleArr[$childkey]     =   (string)$childValue;
          }
          $data[]     =   $singleArr;
       }
    }
   }
   echo '<pre>';print_r($data);

尝试像这样循环解析xml数据。

【讨论】:

  • 它不工作。见下文结果 => SimpleXMLElement Object ( ) [description] => SimpleXMLElement Object ( ) [requirements] => SimpleXMLElement Object ( ) [jobtype] => SimpleXMLElement Object ( ) [category] ​​=> SimpleXMLElement Object ( ) [experience] => SimpleXMLElement Object ( ) [salary] => SimpleXMLElement Object ( ) ) [7] => SimpleXMLElement Object ( [title] => SimpleXMLElement Object ( ) [id] => 129243 [url] => SimpleXMLElement Object ( ) [date] = > 2019 年 6 月 4 日星期二 09:45:50 +0100 [邮编] => 300001 [城市] => SimpleXMLElement Object ( ) [state] => SimpleXMLElement Object ( ) [country] =>
  • 这是一个展示如何循环遍历 xml 数据的示例。
猜你喜欢
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 2018-09-10
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多