1

I am trying to parse an XML file with PHP so that I can replace a certain tag's value.

This is what the relevant XML looks like:

<channel>
    <item>
        <title>Woo Logo</title>
        <link>http://demo2.woothemes.com/woocommerce/product/woo-logo/</link>
        <pubDate>Fri, 07 Jun 2013 10:35:51 +0000</pubDate>
        <dc:creator>wooteam</dc:creator>
        <guid isPermaLink="false">http://demo2.woothemes.com/dummydata/?post_type=product&#038;p=15</guid>
        <description></description>
        <content:encoded><![CDATA[Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.]]></content:encoded>
        <excerpt:encoded><![CDATA[Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.]]></excerpt:encoded>
        <wp:post_id>15</wp:post_id>
        <wp:post_date>2013-06-07 10:35:51</wp:post_date>
        <wp:post_date_gmt>2013-06-07 10:35:51</wp:post_date_gmt>
        <wp:comment_status>open</wp:comment_status>
        <wp:ping_status>closed</wp:ping_status>
        <wp:post_name>woo-logo</wp:post_name>
        <wp:status>publish</wp:status>
        <wp:post_parent>0</wp:post_parent>
        <wp:menu_order>0</wp:menu_order>
        <wp:post_type>product</wp:post_type>
        <wp:post_password></wp:post_password>
        <wp:is_sticky>0</wp:is_sticky>
        <category domain="product_cat" nicename="clothing"><![CDATA[Clothing]]></category>
        <category domain="product_type" nicename="simple"><![CDATA[simple]]></category>
        <category domain="product_cat" nicename="t-shirts"><![CDATA[T-shirts]]></category>
        <wp:postmeta>
            <wp:meta_key>_edit_last</wp:meta_key>
            <wp:meta_value><![CDATA[3]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_thumbnail_id</wp:meta_key>
            <wp:meta_value><![CDATA[16]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_visibility</wp:meta_key>
            <wp:meta_value><![CDATA[visible]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_stock_status</wp:meta_key>
            <wp:meta_value><![CDATA[instock]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>total_sales</wp:meta_key>
            <wp:meta_value><![CDATA[0]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_downloadable</wp:meta_key>
            <wp:meta_value><![CDATA[no]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_virtual</wp:meta_key>
            <wp:meta_value><![CDATA[no]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_product_image_gallery</wp:meta_key>
            <wp:meta_value><![CDATA[17]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_regular_price</wp:meta_key>
            <wp:meta_value><![CDATA[20]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_sale_price</wp:meta_key>
            <wp:meta_value><![CDATA[18]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_tax_status</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_tax_class</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_purchase_note</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_featured</wp:meta_key>
            <wp:meta_value><![CDATA[no]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_weight</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_length</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_width</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_height</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_sku</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_product_attributes</wp:meta_key>
            <wp:meta_value><![CDATA[a:0:{}]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_sale_price_dates_from</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_sale_price_dates_to</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_price</wp:meta_key>
            <wp:meta_value><![CDATA[18]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_sold_individually</wp:meta_key>
            <wp:meta_value><![CDATA[]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_stock</wp:meta_key>
            <wp:meta_value><![CDATA[5]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_backorders</wp:meta_key>
            <wp:meta_value><![CDATA[no]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_manage_stock</wp:meta_key>
            <wp:meta_value><![CDATA[yes]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_upsell_ids</wp:meta_key>
            <wp:meta_value><![CDATA[a:1:{i:0;s:2:"60";}]]></wp:meta_value>
        </wp:postmeta>
        <wp:comment>
            <wp:comment_id>13</wp:comment_id>
            <wp:comment_author><![CDATA[Cobus Bester]]></wp:comment_author>
            <wp:comment_author_email>[email protected]</wp:comment_author_email>
            <wp:comment_author_url></wp:comment_author_url>
            <wp:comment_author_IP>196.215.9.147</wp:comment_author_IP>
            <wp:comment_date>2013-06-07 11:57:05</wp:comment_date>
            <wp:comment_date_gmt>2013-06-07 11:57:05</wp:comment_date_gmt>
            <wp:comment_content><![CDATA[Simple and effective design. One of my favorites.]]></wp:comment_content>
            <wp:comment_approved>1</wp:comment_approved>
            <wp:comment_type></wp:comment_type>
            <wp:comment_parent>0</wp:comment_parent>
            <wp:comment_user_id>0</wp:comment_user_id>
            <wp:commentmeta>
                <wp:meta_key>akismet_error</wp:meta_key>
                <wp:meta_value><![CDATA[1370606225]]></wp:meta_value>
            </wp:commentmeta>
            <wp:commentmeta>
                <wp:meta_key>akismet_history</wp:meta_key>
                <wp:meta_value><![CDATA[a:4:{s:4:"time";d:1370606225.6765859127044677734375;s:7:"message";s:92:"Akismet was unable to check this comment (response: ), will automatically retry again later.";s:5:"event";s:11:"check-error";s:4:"user";s:0:"";}]]></wp:meta_value>
            </wp:commentmeta>
            <wp:commentmeta>
                <wp:meta_key>akismet_as_submitted</wp:meta_key>
                <wp:meta_value><![CDATA[a:67:{s:15:"comment_post_ID";i:15;s:14:"comment_author";s:12:"Cobus Bester";s:20:"comment_author_email";s:18:"[email protected]";s:18:"comment_author_url";N;s:15:"comment_content";s:49:"Simple and effective design. One of my favorites.";s:12:"comment_type";s:0:"";s:14:"comment_parent";i:0;s:7:"user_ID";i:0;s:7:"user_ip";s:13:"196.215.9.147";s:10:"user_agent";s:119:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31";s:8:"referrer";s:56:"http://demo2.woothemes.com/woocommerce/product/woo-logo/";s:4:"blog";s:38:"http://demo2.woothemes.com/woocommerce";s:9:"blog_lang";s:5:"en_US";s:12:"blog_charset";s:5:"UTF-8";s:9:"permalink";s:56:"http://demo2.woothemes.com/woocommerce/product/woo-logo/";s:21:"akismet_comment_nonce";s:6:"passed";s:11:"POST_author";s:12:"Cobus Bester";s:10:"POST_email";s:18:"[email protected]";s:11:"POST_rating";s:1:"4";s:12:"POST_comment";s:49:"Simple and effective design. One of my favorites.";s:7:"POST__n";s:10:"a80bd2f042";s:21:"POST__wp_http_referer";s:30:"/woocommerce/product/woo-logo/";s:11:"POST_submit";s:13:"Submit Review";s:20:"POST_comment_post_ID";s:2:"15";s:19:"POST_comment_parent";s:1:"0";s:26:"POST_akismet_comment_nonce";s:10:"bbd941e9bf";s:15:"SERVER_SOFTWARE";s:6:"Apache";s:11:"REQUEST_URI";s:33:"/woocommerce/wp-comments-post.php";s:15:"REDIRECT_IS_WPE";s:1:"1";s:27:"REDIRECT_WPE_CAN_WRITE_DISK";s:1:"0";s:15:"REDIRECT_STATUS";s:3:"200";s:6:"IS_WPE";s:1:"1";s:18:"WPE_CAN_WRITE_DISK";s:1:"0";s:9:"HTTP_HOST";s:19:"demo2.woothemes.com";s:13:"HTTP_X_LB_KEY";s:8:"woodemo2";s:13:"HTTP_X_IS_BOT";s:1:"0";s:15:"HTTP_USER_AGENT";s:119:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31";s:15:"HTTP_CONNECTION";s:5:"close";s:14:"CONTENT_LENGTH";s:3:"273";s:18:"HTTP_CACHE_CONTROL";s:9:"max-age=0";s:11:"HTTP_ACCEPT";s:63:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";s:11:"HTTP_ORIGIN";s:26:"http://demo2.woothemes.com";s:12:"CONTENT_TYPE";s:33:"application/x-www-form-urlencoded";s:12:"HTTP_REFERER";s:56:"http://demo2.woothemes.com/woocommerce/product/woo-logo/";s:20:"HTTP_ACCEPT_ENCODING";s:17:"gzip,deflate,sdch";s:20:"HTTP_ACCEPT_LANGUAGE";s:14:"en-US,en;q=0.8";s:19:"HTTP_ACCEPT_CHARSET";s:30:"ISO-8859-1,utf-8;q=0.7,*;q=0.3";s:11:"HTTP_COOKIE";s:0:"";s:4:"PATH";s:28:"/usr/local/bin:/usr/bin:/bin";s:16:"SERVER_SIGNATURE";s:0:"";s:11:"SERVER_NAME";s:19:"demo2.woothemes.com";s:11:"SERVER_ADDR";s:9:"127.0.0.1";s:11:"SERVER_PORT";s:2:"80";s:11:"REMOTE_ADDR";s:13:"196.215.9.147";s:13:"DOCUMENT_ROOT";s:26:"/nas/wp/www/sites/woodemo2";s:12:"SERVER_ADMIN";s:18:"[no address given]";s:15:"SCRIPT_FILENAME";s:47:"/nas/wp/www/sites/woodemo2/wp-comments-post.php";s:11:"REMOTE_PORT";s:5:"57596";s:12:"REDIRECT_URL";s:33:"/woocommerce/wp-comments-post.php";s:17:"GATEWAY_INTERFACE";s:7:"CGI/1.1";s:15:"SERVER_PROTOCOL";s:8:"HTTP/1.0";s:14:"REQUEST_METHOD";s:4:"POST";s:12:"QUERY_STRING";s:0:"";s:11:"SCRIPT_NAME";s:21:"/wp-comments-post.php";s:8:"PHP_SELF";s:21:"/wp-comments-post.php";s:12:"REQUEST_TIME";s:10:"1370606225";s:25:"comment_post_modified_gmt";s:19:"2013-06-07 11:15:25";}]]></wp:meta_value>
            </wp:commentmeta>
            <wp:commentmeta>
                <wp:meta_key>rating</wp:meta_key>
                <wp:meta_value><![CDATA[4]]></wp:meta_value>
            </wp:commentmeta>
            <wp:commentmeta>
                <wp:meta_key>akismet_history</wp:meta_key>
                <wp:meta_value><![CDATA[a:4:{s:4:"time";d:1370607940.89634990692138671875;s:7:"message";s:46:"wooteam changed the comment status to approved";s:5:"event";s:15:"status-approved";s:4:"user";s:7:"wooteam";}]]></wp:meta_value>
            </wp:commentmeta>
        </wp:comment>
    </item>
</channel>

I am interested in the wp:postmeta block that has to do with price - the one with <wp:meta_key>_price</wp:meta_key>. Here is what I have tried to do:

$dom=new DOMDocument();
$dom->load("/var/www/wp-content/plugins/woocommerce/dummy-data/nspro.xml");

$root=$dom->documentElement;

$markers=$root->getElementsByTagName('item');

echo $markers->item(0)->getElementsByTagName('wp:postmeta')->item(22)->getElementsByTagName('wp:meta_key')->item(0)->textContent;

This doesn't work - I get this error:

Fatal error: Call to a member function getElementsByTagName() on a non-object.

The error is referencing my call with that function right after $markers->item(0)->getElementsByTagName('wp:postmeta')->item(22)->. Apparently, I can't use it the same way I do when I reference the first <item> in the list. How do I go about accessing the tags inside of the <wp:postmeta> blocks?

9
  • Why not simplexml instead? Commented Sep 4, 2014 at 19:21
  • @Mr.Smith This is just one way I found to do it - if you can provide an example with simplexml and it works I would gladly use that. Commented Sep 4, 2014 at 19:22
  • just saw the link and this: this looks great ill try it <?php $xml = simplexml_load_file($xmlfile); print $xml->City->Street->Address->HouseColor; ?> Commented Sep 4, 2014 at 19:26
  • Yes this is the reason why it is called Simple XML :) Commented Sep 4, 2014 at 19:27
  • @Mr.Smith - im trying with simplexml - can you tell me what i'm doing wrong - you'll probably get what I'm trying to do...echo $xml->channel->item[$startval + $counter]->wp:postmeta[22]->wp:meta_key; I am trying to get the correct item to edit - which is why i'm using counters in a loop - but i'm getting an internal server error so obviously my syntax is off...definitely looks wrong - but im not sure what is right :) Commented Sep 4, 2014 at 19:44

2 Answers 2

5

You did not post something relevant in you example XML. The document element contains namespace definitions (the xmlns:* attributes). The data you're looking for is in the namespace defined by the xmlns:wp attribute.

You can use Xpath to fetch the data in a much more easy and stable way.

$dom = new DOMDocument();
$dom->loadXML($xml);
// create an XPath instance
$xpath = new DOMXpath($dom);
// register a prefix for the wordpress export namespace
$xpath->registerNamespace('wp', 'http://wordpress.org/export/1.0/');

// fetch all rss item element nodes and iterate them
foreach ($xpath->evaluate('//item') as $item) {
  // get the price meta data as a number
  var_dump(
    $xpath->evaluate(
      'number(.//wp:postmeta[wp:meta_key = "_price"]/wp:meta_value)',
      $item
    )
  );
}

Demo: https://eval.in/188516

Output:

float(18)

Now if you want to edit something you need to fetch it as a node. If the Xpath expression is a location path it will always return a node list, much like getElementsByTagName(). You can check if the list contains a value, but I prefer to do the limitation in Xpath and just use foreach().

// inside the item loop
$priceNodes = $xpath->evaluate(
  './/wp:postmeta[wp:meta_key = "_price"][1]/wp:meta_value', $item
);
foreach ($priceNodes as $priceNode) {
  $newPrice = 42; 
  $priceNode->nodeValue = (int)$newPrice;
}

Demo: https://eval.in/188529

Be careful with DOMNode::$nodeValue. Only set values that can not contain a &. PHP has a bug here. Otherwise use it to remove all children and append a new text node.

$priceNode->nodeValue = '';
$priceNode->appendChild($dom->createTextNode($newPrice));
Sign up to request clarification or add additional context in comments.

2 Comments

this works great! im going to google it now but maybe you can save me some trouble and tell me how to replace the wp:meta_value with xpath?
Not exactly with Xpath. DOMXpath is part of ext/dom. You just use the dom functions. I added an example to the answer.
0

So this should work:

$xml = file_get_contents('/var/www/wp-content/plugins/woocommerce/dummy-data/nspro.xml');
$content = simplexml_load_string($xml);

echo $content->item->postmeta[22]->meta_key;

My output of your code in question is:

_price

13 Comments

i tried it as you said and im getting: Notice: Trying to get property of non-object
but I have a variable $startval that is the index for the item that i want to edit - because in my xml file there is more than one item - how do i get like - the 55th item?
i'm thinking $content->item[$startval]->postmeta[22]->meta_key; but that doesn't seem to work.
I don't know how your XML looks like. It looks different in your description as what you posted in your question...
yah it is slightly different - there is just more than one item - i just couldn't post it all in the question - basically after $content there should be an array (or some structure like it) of item's
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.