PHP,XML,访问属性

时间:2011-04-30 14:53:57

标签: php xml xml-attribute

我在访问XML中的属性时遇到了一些麻烦。我的代码如下。最初我有两个循环,这没有问题。

我首先会获取图像名称,然后使用第二个循环来获取故事标题和故事详细信息。然后将所有内容插入数据库。我想整理代码并只使用一个循环。我的图像名称存储在Href属性中。 ()

示例XML布局(http://pastie.org/1850682)。 XML布局有点乱,所以这就是使用两个循环的原因。

$xml = new SimpleXMLElement('entertainment/Showbiz.xml', null, true);

    // Get story images
    //$i=0;
    //$image = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent/NewsComponent/NewsComponent/ContentItem');
  //  foreach($image as $imageNode){
    //  $attributeArray = $imageNode->attributes(); 
    //  if ($attributeArray != ""){
    //      $imageArray[$i] = $attributeArray;
    //      $i++;
    //  }
    //}

// Get story header & detail
$i=0;
$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent');
foreach($story as $contentItem){
    //$dbImage = $imageArray[$i]['Href'];
    foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
        $strDetail = "";
        foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.content/p') as $detail){
            $strDetail .= '<p>'.$detail.'</p>';
            foreach($contentItem->xpath('NewsComponent/NewsComponent/ContentItem') as $imageNode){
                $dbImage = $imageNode->attributes();    
            }
        }

        $link = getUnique($headline);

        $sql = "INSERT INTO tablename (headline, detail, image, link) VALUES ('".mysql_real_escape_string($headline)."', '".mysql_real_escape_string($strDetail)."', '".mysql_real_escape_string($dbImage)."', '".$link."')";
        if (mysql_query($sql, $db) or die(mysql_error())){
            echo "Loaded ";
        }else{
            echo "Not Loaded "; 
        }

    }
    $i++;
}

我想我已经接近了。我尝试在第四个嵌套的foreach循环中放入一些echo语句,但没有任何结果。所以它没有执行那个循环。我已经在这里待了几个小时并且也用Google搜索,但是无法得到它。

如果所有其他方法都失败了,我会回到使用两个循环。

此致 斯蒂芬

1 个答案:

答案 0 :(得分:2)

这很难理解。我简化了结构,因此我们可以看到我们关心的层次结构部分。

simplified XML hierarchy

具有 Duid 属性的NewsComponent似乎是定义/包含一个完整新闻片段的内容。在它的两个子节点中,第一个子节点NewsComponent包含摘要和文本,而第二个子节点NewsComponent包含图像。

您的初始XPath查询是针对'NewsItem/NewsComponent/NewsComponent/NewsComponent'的,这是第一个NewsComponent子级(具有正文文本的子级)。您无法从该点找到图像,因为图像不在该NewsComponent中;你已经走得太深了一层。 (我得到了一个PHP 通知:未定义的变量:dbImage 。)因此,将初始XPath查询放回一个级别,并在需要的时候将额外的级别添加到后续的XPath查询中

由此:

$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent');
foreach($story as $contentItem){
  foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
    foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.content/p') as $detail){
      foreach($contentItem->xpath('NewsComponent/NewsComponent/ContentItem') as $imageNode){ /* ... */ }}}}

到此:

$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent');
foreach($story as $contentItem){
  foreach($contentItem->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
    foreach($contentItem->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.content/p') as $detail){
      foreach($contentItem->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem') as $imageNode){ /* ... */ }}}}

然而,之后图像仍然不起作用。因为您正在使用循环(有时不必要),$dbImage会被重新分配给空字符串。第一个ContentItem具有 Href 属性,该属性被分配给$dbImage。但是它循环到下一个没有属性的ContentItem,因此用空值覆盖$dbImage。我建议修改该XPath查询以仅查找具有 Href 属性的ContentItem,如下所示:

->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem[@Href]')

应该这样做。


其他想法

重构以清除此代码,如果/在可能的情况下。

正如我所提到的,有时候你不需要循环和嵌套,它最终会更难以遵循并可能引入逻辑错误(如图像错误)。看来这个文件的结构总是一致的。如果是这样,您可以放弃一些循环并直接查找您正在寻找的数据。你可以这样做:

// Get story header & detail
$stories = $xml->xpath('/NewsML/NewsItem/NewsComponent/NewsComponent');
foreach ($stories as $story) {
    $headlineItem = $story->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.head/hedline/hl1');
    $headline = $headlineItem[0];

    $detailItems = $story->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.content/p');
    $strDetail = '<p>' . implode('</p><p>', $detailItems) . '</p>';

    $imageItem = $story->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem[@Href]');
    $imageAtts = $imageItem[0]->attributes();
    $dbImage = $imageAtts['Href'];

    $link = getUnique($headline);

    $sql = "INSERT INTO tablename (headline, detail, image, link) VALUES ('".mysql_real_escape_string($headline)."', '".mysql_real_escape_string($strDetail)."', '".mysql_real_escape_string($dbImage)."', '".$link."')";
    if (mysql_query($sql, $db) or die(mysql_error())) {
        echo "Loaded ";
    } else {
        echo "Not Loaded "; 
    }
}