PHP, XML, Доступ к атрибутам - PullRequest
1 голос
/ 30 апреля 2011

У меня возникли проблемы с доступом к атрибутам в моем 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, но ничего не вышло. Так что это не выполняет этот цикл. Я занимался этим несколько часов и тоже погуглил, просто не могу его достать.

Если ничего не помогает, я просто вернусь к использованию двух циклов.

С уважением, Стивен

1 Ответ

2 голосов
/ 01 мая 2011

Это было довольно сложно понять. Я упростил структуру, чтобы мы могли видеть части иерархии, которые нас интересуют.

simplified XML hierarchy

Похоже, что NewsComponent, имеющий атрибут Duid , определяет / содержит одну полную новость. Из двух дочерних элементов 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, чтобы найти только ContentItems, имеющие атрибут Href , например:

->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 "; 
    }
}
...