Viewed   59 times

I have the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<gnm:Workbook xmlns:gnm="http://www.gnumeric.org/v10.dtd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.gnumeric.org/v9.xsd">
  <office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.1">
    <office:meta>
      <dc:creator>Mark Baker</dc:creator>
      <dc:date>2010-09-01T22:49:33Z</dc:date>
      <meta:creation-date>2010-09-01T22:48:39Z</meta:creation-date>
      <meta:editing-cycles>4</meta:editing-cycles>
      <meta:editing-duration>PT00H04M20S</meta:editing-duration>
      <meta:generator>OpenOffice.org/3.1$Win32 OpenOffice.org_project/310m11$Build-9399</meta:generator>
    </office:meta>
  </office:document-meta>
</gnm:Workbook>

And am trying to read the office:document-meta node to extractthe various elements below it (dc:creator, meta:creation-date, etc.)

The following code:

$xml = simplexml_load_string($gFileData);
$namespacesMeta = $xml->getNamespaces(true);
$officeXML = $xml->children($namespacesMeta['office']);
var_dump($officeXML);
echo '<hr />';

gives me:

object(SimpleXMLElement)[91]
  public 'document-meta' => 
    object(SimpleXMLElement)[93]
      public '@attributes' => 
        array
          'version' => string '1.1' (length=3)
      public 'meta' => 
        object(SimpleXMLElement)[94]

but if I try to read the document-meta element using:

$xml = simplexml_load_string($gFileData);
$namespacesMeta = $xml->getNamespaces(true);
$officeXML = $xml->children($namespacesMeta['office']);
$docMeta = $officeXML->document-meta;
var_dump($docMeta);
echo '<hr />';

I get

Notice: Use of undefined constant meta - assumed 'meta' in /usr/local/apache/htdocsNewDev/PHPExcel/Classes/PHPExcel/Reader/Gnumeric.php on line 273
int 0

I assume that SimpleXML is trying to extract a non-existent node "document" from $officeXML, then subtract the value of (non-existent) constant "meta", resulting in forcing the integer 0 result rather than the document-meta node.

Is there a way to resolve this using SimpleXML, or will I be forced to rewrite using XMLReader? Any help appreciated.

 Answers

4

Your assumption is correct. Use

$officeXML->{'document-meta'}

to make it work.

Please note that the above applies to Element nodes. Attribute nodes (those within the @attributes property when dumping the SimpleXmlElement) do not require any special syntax to be accessed when hyphenated. They are regularly accessible via array notation, e.g.

$xml = <<< XML
<root>
    <hyphenated-element hyphenated-attribute="bar">foo</hyphenated-element>
</root>
XML;
$root = new SimpleXMLElement($xml);
echo $root->{'hyphenated-element'}; // prints "foo"
echo $root->{'hyphenated-element'}['hyphenated-attribute']; // prints "bar"

See the SimpleXml Basics in the Manual for further examples.

Friday, November 18, 2022
1

You need to use the namespace when getting the attribute. The android namespace is defined as:

http://schemas.android.com/apk/res/android

So you need to pass that to the attributes() method, like this:

$xml = simplexml_load_string($xmlStr);

echo (string) $xml->application->activity->attributes('http://schemas.android.com/apk/res/android')->name;

Outputs

com.sunil.tweet.MainActivity

Codepad Demo

Saturday, September 17, 2022
3

The elements you're asking about are not part of the default namespace but in a different one. You can see that because they have a prefix in their name separated by the colon:

  ...
  <channel>
    <title>PhotoSpecialist.de</title>
    <!-- title is in the default namespace, no colon in the name -->
    ...
    <g:price>199.00 EUR</g:price>
    ...
    <g:gtin>5022361100576</g:gtin>
    <!-- price and gtin are in a different namespace, colon in the name and prefixed by "g" -->
  ...

The namespace is given with a prefix, here "g" in your case. And the prefix the namespace stands for is defined in the document element here:

<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">

So the namespace is "http://base.google.com/ns/1.0".

When you access the child-elements by their name with the SimpleXMLElement as you currently do:

$a = $node->title;
$b = $node->price;
$c = $node->gtin;

you're looking only in the default namespace. So only the first element actually contains text, the other two are created on-thy-fly and are yet empty.

To access the namespaced child-elements you need to tell the SimpleXMLElement explicitly with the children() method. It creates a new SimpleXMLElement with all the children in that namespace instead of the default one:

$google = $node->children("http://base.google.com/ns/1.0");

$a = $node->title;
$b = $google->price;
$c = $google->gtin;

So much for the isolated example (yes, that's it already).

A full example then could look like (including node-expansion on the reader, the code you had was a bit rusty):

<?php
/**
 * How to parse an XML node with a colon tag using PHP
 *
 * @link http://.com/q/29876898/367456
 */
const HTTP_BASE_GOOGLE_COM_NS_1_0 = "http://base.google.com/ns/1.0";

$url = 'https://my.datafeedwatch.com/static/files/1248/8222ebd3847fbfdc119abc9ba9d562b2cdb95818.xml';

$reader = new XMLReader;
$reader->open($url);

$doc = new DOMDocument;

// move to first item element
while (($valid = $reader->read()) && $reader->name !== 'item') ;

while ($valid) {
    $default    = simplexml_import_dom($reader->expand($doc));
    $googleBase = $default->children(HTTP_BASE_GOOGLE_COM_NS_1_0);
    printf(
        "%s - %s - %s<br />n"
        , htmlspecialchars($default->title)
        , htmlspecialchars($googleBase->price)
        , htmlspecialchars($googleBase->gtin)
    );

    // move to next item element
    $valid = $reader->next('item');
};

I hope this both gives an explanation and broadens the view a little on XMLReader use as well.

Sunday, November 13, 2022
 
masylum
 
1

Use xpath():

$xml = simplexml_load_string($x); // assume XML in $x
$changes = $xml->xpath("//*[starts-with(local-name(), 'change')]");

This will select all nodes starting with change. The // will select them from whatever position in the tree. The results are stored as SimpleXML elements in an array in $changes.

Now change the selected nodes:

foreach ($changes as $change) 
    $change[0] = "New Text";

Take a look at the changed XML:

echo $xml->asXML();

see it working: https://eval.in/231427

Friday, August 19, 2022
 
4

I had the same problem and I'm using Ubuntu 15.10.

In my case, to solve this issue, I installed the package php7.0-xml using the Synaptic package manager, which include SimpleXml. So, after restart my Apache server, my problem was solved. This package came in the Debian version and you can find it here: https://packages.debian.org/sid/php7.0-xml.

Thursday, September 1, 2022
 
jianya
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :