views:

103

answers:

7

I currently have the following code : $content = "

$content = "
<name>Manufacturer</name><value>John Deere</value><name>Year</name><value>2001</value><name>Location</name><value>NSW</value><name>Hours</name><value>6320</value>";

I need to find a method to create and array as name=>value . E.g Manufacturer => John Deere. Can anyone help me with a simple code snipped ? I tried some regex but doesn't even work to extract the names or values (e.g

$pattern = "/Manufacturer(.*)/";
  preg_match_all($pattern, $content, $matches);
  $st_selval = $matches[1][0];

) I appreciate your time

+4  A: 

You don't want to use regex for this. Try out something like SimpleXML

EDIT
Well, why don't you start with this:

<?php

$content = "<root>" . $content . "</root>";
$xml = new SimpleXMLElement($c);
print_r($xml);

?>

EDIT 2
Despite the fact that some of the answers posted using regular expression MAY work, you should get in the habit of using the correct tool for the job and regular expressions are not the correct tool for parsing of XML.

sberry2A
ok but how do I associate the results in a single array ?
Michael
also the content doesn't seem to be valid xml so I'm getting some kind of errors like SimpleXMLElement::__construct() [simplexmlelement.--construct]: Entity: line 3: parser error : Extra content at the end of the document in C:\wamp\www\index.php on line 13
Michael
This doesn't look like "real world xml", it's just a sequence of tags.
rubber boots
A: 

I'll edit as my PHP is wrong, but here's some PHP (pseudo-)code to give some direction.

$pattern = '|<name>([^<]*)</name>\s*<value>([^<]*)</value>|'
preg_match_all($pattern, $content, $matches, PREG_SET_ORDER);
for($i = 0; $i < count($matches); $i++) {
    $arr[$matches[$i][1]] = $matches[$i][2];
}

$arr is the array you want to store the name/value pairs.

palswim
+1  A: 

First of all, never use regex to parse xml...

You could do this with an XPATH query...

First, wrap the content in a root tag to make the parser happy (if it doesn't already have it):

$content = '<root>' . $content . '</root>';

Then, load the document

$dom = new DomDocument();
$dom->loadXml($content);

Then, initialize the XPATH

$xpath = new DomXpath($dom);

Write your query:

$xpathQuery = '//name[text()="Manufacturer"]/follwing-sibling::value/text()';

Then, execute it:

$manufacturer = $xpath->evaluate($xpathQuery);

If I did the xpath right, it $manufacturer should be John Deere...

You can see the docs on DomXpath, a basic primer on XPath, and a bunch of XPath examples...

Edit: That won't work (PHP doesn't support that syntax (following-sibling). You could do this instead of the xpath query:

$xpathQuery = '//name[text()="Manufacturer"]';
$elements = $xpath->query($xpathQuery);
$manufacturer = $elements->item(0)->nextSibling->nodeValue;
ircmaxell
The article actually says that it's all right to use regex for simple strings.
palswim
unfortunately it's not working it says Warning: domdocument::domdocument() expects at least 1 parameter, 0 given in C:\wamp\www\index.php on line 7Fatal error: Call to undefined method domdocument::loadXml() in C:\wamp\www\index.php on line 8
Michael
What version of PHP are you using? 4? And no, IMHO it's never alright to use regex even for simple xml strings. That's like saying it's alright to use `goto` for simple things...
ircmaxell
+1 for `goto` reference, and for pointing out that REGEX is not for parsing even simple XML.
sberry2A
A: 

This is rather simple, can be solved by regex. Should be:

$name  = '<name>\s*([^<]+)</name>\s*';
$value = '<value>\s*([^<]+)</value>\s*';

$pattern = "|$name $value|";
preg_match_all($pattern, $content, $matches);

# create hash
$stuff = array_combine($matches[1], $matches[2]);

# display
var_dump($stuff);

Regards

rbo

rubber boots
+1  A: 

I'm using your $content variable:

$preg1 = preg_match_all('#<name>([^<]+)#', $content, $name_arr);
$preg2 = preg_match_all('#<value>([^<]+)#', $content, $val_arr);
$array = array_combine($name_arr[1], $val_arr[1]);
nush
quick and simple :) thanks a lot !
Michael
A: 

Using XMLReader:

$content = '<name>Manufacturer</name><value>John Deere</value><name>Year</name><value>2001</value><name>Location</name><value>NSW</value><name>Hours</name><value>6320</value>';
$content = '<content>' . $content . '</content>';
$output = array();

$reader = new XMLReader();
$reader->XML($content);
$currentKey = null;
$currentValue = null;
while ($reader->read()) {
    switch ($reader->name) {
        case 'name':
            $reader->read();
            $currentKey = $reader->value;
            $reader->read();
            break;
        case 'value':
            $reader->read();
            $currentValue = $reader->value;
            $reader->read();
            break;
    }
    if (isset($currentKey) && isset($currentValue)) {
        $output[$currentKey] = $currentValue;
        $currentKey = null;
        $currentValue = null;
    }
}

print_r($output);

The output is:

Array
(
    [Manufacturer] => John Deere
    [Year] => 2001
    [Location] => NSW
    [Hours] => 6320
)
Edward Mazur
A: 

I think this is what you're looking for:

<?php
$content = "<name>Manufacturer</name><value>John Deere</value><name>Year</name><value>2001</value><name>Location</name><value>NSW</value><name>Hours</name><value>6320</value>";
$pattern = "(\<name\>(\w*)\<\/name\>\<value\>(\w*)\<\/value\>)";
preg_match_all($pattern, $content, $matches);

$arr = array();

for ($i=0; $i<count($matches); $i++){
    $arr[$matches[1][$i]] = $matches[2][$i];    
}

/* This is an example on how to use it */
echo "Location: " . $arr["Location"] . "<br><br>";

/* This is the array */
print_r($arr);

?>

If your array has a lot of elements dont use the count() function in the for loop, calculate the value first and then use it as a constant.

Curro