Как разобрать XML с помощью ссылки xhtml: в PHP? - PullRequest
0 голосов
/ 15 февраля 2019

Цель:

  • импортировать внешний файл XML (в данном примере это встроенный файл)
  • получить , сохранить в переменную
  • найти с атрибутом href-lang = "fr-ca", получить значение href, сохранить в переменную
  • вставить оба в БД

Проблема Iиметь: я не могу заставить PHP даже распознать, что ссылка xhtml: является дочерним узлом элемента ;даже когда я просто выкладываю nodeValue для , он пропускает все дочерние узлы .

Код, который я использую / пробовал:

<?php
$xml = <<< XML
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <loc>https://www.example.com/ca/en/cat/categories/series/07660/</loc>
  <lastmod>2018-11-07</lastmod>
  <changefreq>daily</changefreq>
  <priority>1.0</priority>
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-ae" href="https://www.example.com/ae/en/cat/categories/series/07660/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="de-at" href="https://www.example.com/at/de/cat/07660/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-au" href="https://www.example.com/au/en/cat/categories/series/07660/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-ca" href="https://www.example.com/ca/en/cat/categories/series/07660/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="fr-ca" href="https://www.example.com/ca/fr/cat/categories/series/07660/" />
</url>
<url xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <loc>https://www.example.com/ca/en/cat/categories/series/07683/</loc>
  <lastmod>2018-11-07</lastmod>
  <changefreq>daily</changefreq>
  <priority>1.0</priority>
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-ae" href="https://www.example.com/ae/en/cat/categories/series/07683/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="de-at" href="https://www.example.com/at/de/cat/07683/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-au" href="https://www.example.com/au/en/cat/categories/series/07683/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="fr-be" href="https://www.example.com/be/fr/collections/07683/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="nl-be" href="https://www.example.com/be/nl/collecties/07683/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-bh" href="https://www.example.com/bh/en/cat/07683/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="en-ca" href="https://www.example.com/ca/en/cat/categories/series/07683/" />
  <xhtml:link xmlns:xhtml="http://www.w3.org/1999/xhtml" rel="alternate" hreflang="fr-ca" href="https://www.example.com/ca/fr/cat/categories/series/07683/" />
</url>
</urlset>
XML;

$urlsxml = new DOMDocument;
$urlsxml->loadXML($xml);
$urls = $urlsxml->getElementsByTagName('url');

for ($i = 0; $i < $urls->length; $i++) {

      echo $urls->item($i)->nodeValue;
      echo $urls->getElementsByTagName("xhtml:link")->attributes->getNamedItem("hreflang")->nodeValue;

      // INSERT INTO DB

}

?>

Из идей;любая помощь будет оценена.

Ответы [ 3 ]

0 голосов
/ 16 февраля 2019

Если вы поместите ваш XML-файл в переменную, вы можете извлечь значения с помощью цикла:

$xml = file_get_contents("your_xml_file");
$tags = explode("<", $xml);
$loc = "not found";
$frhref = "not found";

foreach ($tags as $tag){
    if(strpos($tag, "loc>") === 0){
        $loc = substr($tag, 4);
    }
    if(strpos($tag, "xhtml:link") === 0){
        $at = strpos($tag, "hreflang") + 9;
        $lang = substr($tag, $at, 7);
        if($lang == '"fr-ca"'){
            $at = strpos($tag, "href=") + 6;
            $_href = substr($tag, $at);
            $until = strpos($_href, '"');
            $frhref = substr($_href, 0, $until);
        }
    }
}
echo $loc, " ", $frhref; //put them in your db

Я проверил его с вашим контентом: https://3v4l.org/1laON

0 голосов
/ 19 февраля 2019

XML использует два пространства имен http://www.sitemaps.org/schemas/sitemap/0.9 без псевдонима и http://www.w3.org/1999/xhtml с псевдонимом xhtml.Чтобы читать XML с пространствами имен, вы должны использовать *NS варианты методов DOM.

$urls = $urlsxml->getElementsByTagNameNS(
  'http://www.sitemaps.org/schemas/sitemap/0.9', 'url'
);

$urls[$i]->getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'link');

Первый аргумент - это URI пространства имен, второй аргумент - локальное имя (имя узла с префиксом).В этом случае было бы неплохо использовать константу / переменную для URI пространства имен.

Более удобным вариантом является Xpath.Он позволяет использовать пути и условия местоположения для извлечения узлов.

$document = new DOMDocument;
$document->loadXML($xml);
// create an xpath instance for the document
$xpath = new DOMXpath($document);
// register the namespaces for your own prefixes
$xpath->registerNameSpace('s', 'http://www.sitemaps.org/schemas/sitemap/0.9');
$xpath->registerNameSpace('x', 'http://www.w3.org/1999/xhtml');

// iterate all sitemap url elements
foreach ($xpath->evaluate('//s:url') as $url) {
  $data = [
    // get the sitemap loc child element as a string
    'loc' => $xpath->evaluate('string(s:loc)', $url),
    // get the href attribute of the xhtml link element (with language condition)
    'fr-ca' => $xpath->evaluate('string(x:link[@hreflang="fr-ca"]/@href)', $url),
  ];
  var_dump($data);
}

Вывод:

array(2) { 
  ["loc"]=> 
  string(58) "https://www.example.com/ca/en/cat/categories/series/07660/" 
  ["fr-ca"]=> 
  string(58) "https://www.example.com/ca/fr/cat/categories/series/07660/" 
} 
array(2) { 
  ["loc"]=> 
  string(58) "https://www.example.com/ca/en/cat/categories/series/07683/" 
  ["fr-ca"]=> 
  string(58) "https://www.example.com/ca/fr/cat/categories/series/07683/" 
}

string() в Xpath преобразует первый узел в списке в строку.Это позволяет вам избежать явного доступа к свойствам объекта узла.Например, $xpath->evaluate('s:loc', $url)->item(0)->textContent; можно записать как $xpath->evaluate('string(s:loc)', $url);.В отличие от доступа к свойству, приведение Xpath не завершится с ошибкой, если не существует соответствующего узла.Он вернет пустую строку.

0 голосов
/ 16 февраля 2019

Фактический процесс вставки в вашу базу данных выходит за рамки этого кода, но для анализа XML вы можете сделать что-то простое (например, на основе локальной сохраненной копии XML, а не с использованием синтаксиса heredoc).) ~ имя файла предназначено только для идентификации.

Первоначально я думал, что для этого потребуется зарегистрировать и использовать namespace в выражениях XPath, но это было не так - простой запрос XPath для каждогоurl узла было достаточно ~ с использованием родительского узла url в качестве ссылочного узла для запроса.

$file='so-stack-xml-namespace.xml';


libxml_use_internal_errors( true );
$dom=new DOMDocument;
$dom->validateOnParse=true;
$dom->recover=true;
$dom->strictErrorChecking=true;
$dom->load( $file );
libxml_clear_errors();

$xp=new DOMXPath( $dom );

$urls=$dom->getElementsByTagName('url');
foreach( $urls as $url ){
    $href=$url->nodeValue;
    $frca=$xp->query('xhtml:link[@hreflang="fr-ca"]',$url)->item(0)->getAttribute('href');
    /* do something with the variables...add to DB */
    printf('href:%s<br />frca:%s<br /><br />', $href,$frca);
}
...