[PHP/regex] Tagnaam, Attributen en content filteren

Pagina: 1
Acties:
  • 260 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 20:33
Ik wil een xml bestand inlezen met php. Ben nu al een paar dagen aan het klooien met regex en het gaat steeds beter, toch loop ik vast.

Dit is de regex zoals ik hem nu heb:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/<([a-zA-z][a-zA-z0-9]*)([^>]*)(\/>|>([.(?!<\/\\1>)]*)<\/\\1>)/s

Even opsplitsen voor mijn gedachtegang

/
<                       // Opentag
([a-zA-z][a-zA-z0-9]*)  // Tagnaam
([^>]*)                 // Alle attributen als 1 string

(\/>                    // Zelf sluitende tag

|                       // OF

>                       //Dicht
([.(?!<\/\\1>)]*)       //Alle chars zolang maar niet gevolgt door een sluitende tag met Opentag

<\/\\1>)                // Een sluittag

/s                      // Einde regex, let niet op whitespace


Met deze regex heb ik het probleem dat hij alleen zelf sluitende tags pakt. Voordat ik deze had aangepast had ik hem zonder de lookahead. Echter was de regex toen greedy. Waardoor hij de eerste opentag ( = <tagnaam >) en de laatste sluittag ( = </tagnaam>) pakte.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/<([a-zA-z][a-zA-z0-9]*)([^>]*)(\/>|>(.*)<\/\\1>)/s

even opslitsen:

/
<                          // Opentag
([a-zA-z][a-zA-z0-9]*)     // Tagnaam
([^>]*)                    // Alle attributen als 1 string

(\/>                       // Zelf sluitende tag

|                          // OF

>                          //Dicht
(.*)                       //Alle chars

<\/\\1>)                   // Een sluittag

/s                         // Einde regex, let niet op whitespace


Het lijkt me duidelijk dat deze greedy is. Met zelfsluitende tags werkt dit echter wel.

Hoe maak ik de laatste regex non-greedy op de bijbehoorden sluittag?

[ Voor 5% gewijzigd door storeman op 12-03-2007 16:10 ]

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • RubenDJ
  • Registratie: Februari 2000
  • Laatst online: 13:54
Waarom geen kant en klare functies gebruiken?

DOM XML (php4)
of
Simple XML (php5)

Dan wordt al dat regex'en voor je gedaan ;)

specs


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 20:33
RubenDJ schreef op maandag 12 maart 2007 @ 16:12:
Waarom geen kant en klare functies gebruiken?

DOM XML (php4)
of
Simple XML (php5)

Dan wordt al dat regex'en voor je gedaan ;)
Die simpleXML had ik al gevonden, alleen zit ik met php4. Ik meende het ooit al eens gezien te hebben, kon het alleen niet meer vinden. Thnx _/-\o_ .

Heb ik net zo'n mooie klasse geschreven die het geheel inleest }:O .

Naja, moeilijk doen als het makkelijk kan.

Ik ben echter nog steeds benieuwd naar het antwoord! >:)

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • Mr. Bondt
  • Registratie: Februari 2005
  • Laatst online: 27-08 14:50
code:
1
/<([a-zA-z][a-zA-z0-9]*)([^>]*)(\/>|>(.*?)<\/\\1>)/s

Non-greedy :Y)

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

XML:
1
2
3
4
5
6
7
<root>
    <content><![CDATA[
        tralala
        </content>
        hiephoi
    ]]></content>
</root>


:P

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 20:33
Achja, details....
Eerst een regexje om dat eruit te pleuren :), kan ie daar niet meer de mist mee ingaan

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

storeman schreef op dinsdag 13 maart 2007 @ 09:31:
Achja, details....
Eerst een regexje om dat eruit te pleuren :), kan ie daar niet meer de mist mee ingaan
sure, greedy of non-greedy?
XML:
1
2
3
4
5
6
7
8
9
10
<root>
    <content><![CDATA[
        </content>
        <![CDATA[
        tralala
    ]]></content>
    <content><![CDATA[
        nog meer
    ]]></content>
</root>


Het is gewoonweg geen goed idee om dit soort dingen regexp-based te 'parsen'...

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 20:33
Moet ik je gelijk in geven. Kan maar beter de domfuncties gebruiken. Wel zo veilig.

thnx anyways

Wat doet het eigenlijk? Ik meende dat het commentaar was, maar dat is het niet. Wat is het wel?

Ben al bezig @ w3school :)

[ Voor 40% gewijzigd door storeman op 13-03-2007 10:50 ]

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 20:33
Okee, weer ff geprutst, volgens mij voldoet dit toch echt aan je eisen:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
define("XMLMatchCDData", "/<!\[CDATA\[(.*?)\]\]>/s");

$this->_oFile = new File($Filename);

// First remove the header
$_strFileData = preg_replace(XMLMatchHeader, "", $this->_oFile->GetContent());

// Replace CDATA, meaning that the < and & have to be replaced
// First find all the CDATA tags
$arrCData = array();
preg_match_all(XMLMatchCDData, $_strFileData, $arrCData);

// The characters to be replaced by the strings
$arrCharSearch = array("&", "<", ">", "'", '"');
$arrCharReplace = array("&amp;", "&lt;", "&gt;", "&apos;", "&quot;");

// The data will be saved in those arrays
$arrSearchData = array();
$arrReplaceData = array();

// Get all the original data from the xml file, including the cdata tags
foreach($arrCData[0] as $value)
    $arrSearchData[] = $value;

// Get the original data, without tags, replace the chars.
foreach($arrCData[1] as $value)
    $arrReplaceData = str_replace($arrCharSearch, $arrCharReplace, $value);

$_strFileData = str_replace($arrSearchData, $arrReplaceData, $_strFileData);

echo $_strFileData;


Voorbeeldje:

input:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
<content><![CDATA[ 
        </content> 
        <![CDATA[ 
        tralala 
    ]]></content> 
    <content><![CDATA[ 
    
    <![CDATA[
    <![CDATA[
    ]    
    ] >
        nog meer 
    ]]></content>  


Door de code rammen:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<content> 
    
    &lt;![CDATA[
    &lt;![CDATA[
    ]    
    ] &gt;
        nog meer 
    </content> 
    <content> 
    
    &lt;![CDATA[
    &lt;![CDATA[
    ]    
    ] &gt;
        nog meer 
    </content> 

>:)

Hmm, klein detail met het & teken :) Solved

[ Voor 20% gewijzigd door storeman op 13-03-2007 11:30 . Reden: voorbeeldje toegevoegd ]

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Mwa, doe dan gewoon zoiets:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$pos = 0;
$out = '';
while ($pos < strlen($xml) && ($s = strpos($xml, '<![CDATA[', $pos)) !== false)
{
    $out .= substr($xml, $pos, $s - $pos);
    $pos = $s + 9;

    $e = strpos($xml, ']]>', $pos);
    if ($e === false) $e = strlen($xml);

    $out .= htmlspecialchars(substr($xml, $pos, $e - $pos));
    $pos = $e + 3;
}
$out .= substr($xml, $pos);

Intentionally left blank

Pagina: 1