2012-06-11 15 views
7

Piszę skrypt, który pobiera stronę internetową i wykrywa, ile razy używa się takich rzeczy jak przycisk na facebooku. Ponieważ najlepiej byłoby to zrobić z DOM, postanowiłem użyć DOMDocument PHP.Przestrzenie nazw DOMDocument PHP

Jeden problem mam natknąć, choć jest dla elementów, takich jak Facebook jest jak przycisk:

<fb:like send="true" width="450" show_faces="true"></fb:like> 

Ponieważ ten element technicznie posiada przestrzeń nazw „fb” DOMDocument generuje ostrzeżenie mówiąc to namespace prefix Nie określono. Następnie przystępuje do zerwania prefiksu, więc kiedy dojdę do tego elementu, jego znacznik nie jest już fb: jak, ale zamiast tego jak.

Czy istnieje sposób "wstępnej rejestracji" obszaru nazw? Jakieś sugestie?

Odpowiedz

0

miałem ten sam problem i wymyśliłem następujące rozwiązania/obejścia:

Nie ma czysty sposób analizowania HTML z nazw korzystających domDocument bez utraty przestrzeni nazw, ale istnieją pewne obejścia:

  • Użyj innego parsera, który akceptuje przestrzenie nazw w kodzie HMTL. Poszukaj ładnej i szczegółowej listy analizatorów HTML. Jest to prawdopodobnie najbardziej skuteczny sposób na zrobienie tego.
  • Jeśli chcesz pozostać przy DOMDocument, musisz najpierw dokonać wstępnego i późniejszego przetworzenia kodu.

    • Przed wysłaniem kodu do Początek rozdziału> loadHTML, użyć wyrażenia regularnego, pętle lub cokolwiek chcesz znaleźć wszystkie znaczniki przestrzeni nazw i dodać atrybut niestandardowy znaczników otwierających zawierających do nazw.

      <fb:like send="true" width="450" show_faces="true"></fb:like> 
      

      by następnie doprowadzić

      <fb:like xmlNamespace="fb" send="true" width="450" show_faces="true"></fb:like> 
      
    • teraz dać zmodyfikowany kod do Początek rozdziału> loadHTML. Będzie to rozebrać się z nazw, ale będzie ona zachować atrybuty powodując

      <like xmlNamespace="fb" send="true" width="450" show_faces="true"></like> 
      
    • Teraz (znów za pomocą wyrażenia regularnego, pętle lub cokolwiek chcesz) znaleźć wszystkie znaczniki z Przestrzenie nazw w XML atrybut i zastąpić atrybut z rzeczywistej przestrzeni nazw. Nie zapomnij również dodać przestrzeni nazw do zamykających tagów!

Nie sądzę OP wciąż szuka odpowiedzi, po prostu księgowania to dla nikogo, że znajdzie ten post w swoich badaniach.

+0

to brzmiało jak bardzo proste rozwiązanie, więc zdecydowałem się na jego uruchomienie.Tutaj jest kod, który zakończył się dla każdego, kto nienawidzi regex.'// zapisz dowolne nazwy rozmieszczone w oddzielnych elementach, abyśmy mogli ponownie je dodać później' '$ postContent = preg_replace ('/ <(\ w +): (\ w +) /', '<\ 1 namespace =" \ 2 " ", $ postContent);' '// ponownie skonstruuj dowolne znaczniki z odstępami między nazwami ' ' $ postContent = preg_replace ('/<(\ w +) namespace = "(\ w +)"/',' <\ 1 : \ 2 ', $ postContent); ' – lupos

0

Czy tego właśnie szukasz?

Możesz spróbować SimpleHTMLDOM. Następnie możesz uruchomić coś w rodzaju ...

$html = new simple_html_dom(); 
$html->load_file('fileToParse.html'); 
$count=0; 
foreach($html->find('fb:like') as $element){ 
    $count+=1 
} 
echo $count; 

To powinno zadziałać.

Poszedłem trochę dalej i znalazłem to. Wziąłem to z DOMDocument na PHP.net.

$dom = new DOMDocument; 
$dom->loadHTML('fileToParse.html'); // or $dom->loadXML('fileToParse.html'); 
$likes = $dom->getElementsByTagName('fb:like'); 
$count=0; 
foreach ($likes as $like) { 
    $count+=1; 
} 

Po tym jednym jestem zatrzymany

$file=file_get_contents("other.html"); 
$search = '/<fb:like[^>]*>/'; 
$count = preg_match_all($search , $file, $matches); 
echo $count; 
//Below is not needed 
print_r($matches); 

To jednak jest RegEx i jest dość powolny. Próbowałem:

$dom = new DOMDocument; 
$xpath = new DOMXPath($dom); 
$dom->load("other.html"); 
$xpath = new DOMXPath($dom); 
$rootNamespace = $dom->lookupNamespaceUri($dom->namespaceURI); 
$xpath->registerNamespace('fb', $rootNamespace); 
$elementList = $xpath->query('//fb:like'); 

Ale dostałem ten sam błąd co ty.

+0

używałem to już wcześniej, ale chciałem użyć rodzimego rozwiązania ze względu na szybkość. Być może będę musiał wrócić do tego domyślnie :( – Obto

+0

@Oto używam tego na moich małych stronach, więc nie mam problemów z szybkością – Bonzo

+0

Zaktualizowałem to dla innego rozwiązania, które powinno być szybsze – Bonzo

4

Możesz użyć tidy, aby świecić rzeczy przed użyciem parsera xml na nim.

$tidy = new tidy(); 
$config = array(
    'output-xml' => true, 
    'input-xml' => true, 
    'add-xml-decl' => true, 
); 
$tidy->ParseString($htmlSoup, $config); 
$tidy->cleanRepair(); 
echo $tidy; 
0

nie udało się znaleźć sposób, aby to zrobić z DOM. Jestem zaskoczony, że regex jest wolniejszy niż DOMDocument, co zwykle nie dotyczy mnie. strpos powinien być najszybszy, choć:

strpos($dom, '<fb:like'); 

Znajduje to tylko pierwszy wystąpieniu, ale można napisać prosty funkcji rekurencyjnej, który zmienia przesunięcie odpowiednio.

1

Ponieważ to nigdy nie zostało "rozwiązane", zdecydowałem się wdrożyć rozwiązanie syndance dla każdego, kto nie lubi wymyślać wyrażeń regularnych.

// do this before you use loadHTML()  
// store any name spaced elements so we can re-add them later 
$postContent = preg_replace('/<(\w+):(\w+)/', '<\1 data-namespace="\2"' , $postContent); 

// once you are done using domdocument fix things up 
// re-construct any name-spaced tags 
$postContent = preg_replace('/<(\w+) data-namespace="(\w+)"/', '<\1:\2 ' , $postContent); 
-1

próbowałem regex-rozwiązanie ... istnieje problem z znacznikach zamykających, ponieważ nie przyjmują atrybuty!

<ns namespace="node">text</ns> 

(przede wszystkim regex nie szukać znaczników zamykających ...) więc wreszcie zrobiłem pewne brzydkie rzeczy jak

$output = preg_replace('/<(\/?)(\w+):(\w+)/', '<\1\2thistaghasanamespace\3' , $output); 

i

$output = preg_replace('/<(\/?)(\w+)thistaghasanamespace(\w+)/', '<\1\2:\3' , $output);