2009-07-05 9 views
7

Mam ciąg z atrybutów HTML:PHP - podzielić ciąg atrybutów HTML do tablicy indeksowanej

$attribs = ' id= "header " class = "foo bar" style ="background-color:#fff; color: red; "'; 

Jak przekształcić ten ciąg do tablicy indeksowanej, jak:

array(
    'id' => 'header', 
    'class' => array('foo', 'bar'), 
    'style' => array(
    'background-color' => '#fff', 
    'color' => 'red' 
) 
) 

dzięki czemu mogę użyć funkcji array_merge_recursive PHP do scalenia 2 zestawów atrybutów HTML.

Dziękuję

Odpowiedz

8

Można użyć wyrażenia regularnego wyodrębnić te informacje:

$attribs = ' id= "header " class = "foo bar" style ="background-color:#fff; color: red; "'; 
$pattern = '/(\\w+)\s*=\\s*("[^"]*"|\'[^\']*\'|[^"\'\\s>]*)/'; 
preg_match_all($pattern, $attribs, $matches, PREG_SET_ORDER); 
$attrs = array(); 
foreach ($matches as $match) { 
    if (($match[2][0] == '"' || $match[2][0] == "'") && $match[2][0] == $match[2][strlen($match[2])-1]) { 
     $match[2] = substr($match[2], 1, -1); 
    } 
    $name = strtolower($match[1]); 
    $value = html_entity_decode($match[2]); 
    switch ($name) { 
    case 'class': 
     $attrs[$name] = preg_split('/\s+/', trim($value)); 
     break; 
    case 'style': 
     // parse CSS property declarations 
     break; 
    default: 
     $attrs[$name] = $value; 
    } 
} 
var_dump($attrs); 

Teraz wystarczy przeanalizować klas class (rozszczepiony na whitespaces) oraz oświadczeń majątkowych style (a trochę trudniejsze, ponieważ może zawierać komentarze i adresy URL z ;).

+0

Dziękuję Gumbo, Twój regex jest super. Jedyny problem to: $ attrs ['class'] lub $ attrs ['style'] zwracają ciągi znaków: więc trudno będzie je połączyć z innym łańcuchem $ attribs, na przykład łącząc 2 zestawy atrybutów: $ attribs1 = 'class = "foo bar"'; $ attribs2 = 'class = "lorem"'; do "class =" foo bar lorem "' Dlatego chciałbym, aby $ attrs [' class '] zwróciło tablicę: array (' foo ',' bar ') Czy masz pomysł, aby to ulepszyć ? – abernier

+0

Naprawdę kocham to rozwiązanie ... ale nie dostaję regex xD to trochę za dużo dla mojej głowy – lumio

+1

Właśnie napisałem alternatywne wyrażenie regularne, które również parsuje atrybuty boolowskie w stylu HTML5 (bez znaku =) i używa odwołania wstecznego do cytatów: '(\ w +) \ s * (= \ s * ([" ']) (. *?) \ 2 \ s)? ' –

2

Może być to pomaga .. Co robi ..

  • html parser DOM napisany w PHP5 + pozwalają manipulować HTML w bardzo prosty sposób!
  • Wymagaj PHP 5+.
  • Obsługuje nieprawidłowy kod HTML.
  • Znajdź znaczniki na stronie HTML z selektorami takimi jak jQuery.
  • Wyciąg zawartość z HTML w jednym wierszu.

http://simplehtmldom.sourceforge.net/

+0

Zauważ, że jednym z powodów, dla których tu trafiłem, jest ponieważ DOMProcessingInstruction ma pole 'data', które jest tekstem z' ' .W przypadku tagu takiego jak: '' otrzymujesz zwykły ciąg znaków, taki jak: 'type =" text/xsl "href =" https://sms.m2osw.com/sitemap.xsl "' które trzeba przeanalizować jako atrybuty: –

3

Nie można użyć wyrażenia regularnego do analizowania HTML atrybuty. Jest tak dlatego, że składnia jest kontekstowa. Można użyć wyrażeń regularnych do tokenizacji danych wejściowych, ale do ich analizy potrzebny jest komputer stanu.

Jeśli wydajność nie jest wielka, najbezpieczniejszym sposobem na to jest prawdopodobnie zawijanie atrybutów w tag, a następnie wysyłanie go za pomocą analizatora html. Np .:

function parse_attributes($input) { 
    $dom = new DomDocument(); 
    $dom->loadHtml("<foo " . $input. "/>"); 
    $attributes = array(); 
    foreach ($dom->documentElement->attributes as $name => $attr) { 
    $attributes[$name] = $node->value; 
    } 
    return $attributes; 
} 

Można prawdopodobnie optymalizacji powyższego, poprzez ponowne parsera, lub za pomocą XmlReader lub sax parser.

+0

Parsuj to: foo = 'bar' cuux = "O'Reiley" zip = "\" zap \ "" – troelskn

+0

@ troelskn: Trzecia deklaracja wartości atrybutu jest nieprawidłowa. być reprezentowane przez odniesienia do znaków. – Gumbo

+0

Masz rację - nie wiedziałem o tym. Wciąż chciałbym zaproponować użycie parsera xml/html, aby uwzględnić wszystkie rodzaje przypadków o skrajnych krawędziach. – troelskn

17

Zastosowanie SimpleXML:

<?php 
$attribs = ' id= "header " class = "foo bar" style ="background-color:#fff; color: red; "'; 

$x = new SimpleXMLElement("<element $attribs />"); 

print_r($x); 

?> 

ta zakłada, że ​​atrybuty są zawsze nazwa/wartość par ...

1

łatwy sposób może być również:

 
$atts_array = current((array) new SimpleXMLElement("<element $attribs />"));