SimpleXMLElement仅解析xml内容的第一个字段

I have a little bit strange problem. I have some internal website which is sharing something which meant to be similar to rssfeed. I mean site with XML content with some crucial information.

Simple entry (there are dozen of entries )of the XML looks like:

<?xml version='1.0' encoding='UTF-8'?>
<nvd xmlns:scap-core="http//0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:patch="http//patch/0.1" xmlns="http//obj/0.1" xmlns:lang="http//lang/2.0" xmlns:cvss="http//cvss-v2/0.2" xmlns:object="http//object/0.4" nvd_xml_version="2.0" pub_date="2014-02-25T10:00:00" xsi:schemaLocation="http//patch/0.1 http//schema/patch_0.1.xsd http//0.1 http//schema/scap-core_0.1.xsd http//obj/0.1 http//schema/nvd-cve-feed_2.0.xsd">
  <entry id="0528">
    <object:configuration id="site.com/">
      <lang:logical-test negate="false" operator="OR">
        <lang:fact-ref name="version:2.6.0"/>
        <lang:fact-ref name="version:2.6.1"/>
        <lang:fact-ref name="version:2.6.2"/>
        <lang:fact-ref name="version:2.6.3"/>
      </lang:logical-test>
    </object:configuration>
    <object:list>
      <object:product>version:2.6.3</object:product>
      <object:product>version:2.6.0</object:product>
      <object:product>version:2.6.1</object:product>
      <object:product>version:2.6.2</object:product>
    </object:list>
    <object:id>0528</object:id>
    <object:published-datetime>2014-02-17T11:55:04.787-05:00</object:published-datetime>
    <object:last-modified-datetime>2014-02-21T09:14:10.780-05:00</object:last-modified-datetime>
    <object:cwe id="264"/>
  </entry>

I would like to read this XML in order to put those values in my database. My approach is like that:

$ch = curl_init();

   if (FALSE === $ch)
       throw new Exception('failed to initialize');

curl_setopt($ch, CURLOPT_URL,"internal.adres.com");
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$content = curl_exec($ch);
$xml = new SimpleXMLElement($content);

foreach ($xml as $obj){
    var_dump($obj);
    break;
}

And here is where magic happens. When I execute var_dump($xml) i get list of objects but those objects have only id field (rest of fields like product or datetime are missing)

result of var_dump($obj) is as follows:

object(SimpleXMLElement)#3 (1) { ["@attributes"]=> array(1) { ["id"]=> string(13) "0528" } } 

How can i get all fields of this xml ?

You are looking at attributes of <entry> field. Loop <entry> for <obj>

Simplifying the XML you supplied (removing the namespaces, correcting a closign tag and giving it a header), I have put together the following example.

It shows some of the different methods you can use to access attributes and nodes in your document.

In short:

  • Attributes can be referenced as array elements of the node.
    • E.g. $node['id']
  • Child nodes can be referenced as member variables, which can then be looped over as arrays.
    • E.g. $node->subNode or foreach( $node->subNode as $subNode )
  • You can chain references together
    • E.g. $node->subNode[0]['id']

I hope the following example makes sense with your structure...

<?

$content = '<?xml version="1.0"?>
<entries>
  <entry id="0528">
    <configuration id="google.com">
      <logical negate="false" operator="OR">
        <fact name="1.0.0"/>
      </logical>
    </configuration>
    <list>
      <product>1.0.0</product>
    </list>
    <id>0528</id>
    <datetime>2014-02-17T11:55:04.787-05:00</datetime>
    <last-modified-datetime>2014-02-21T09:14:10.780-05:00</last-modified-datetime>
  </entry>
</entries>';


$xml = new SimpleXMLElement($content);

foreach ($xml as $entry){

    // attributes can be referenced as array elements
    $entryId = $entry['id'];

    echo( "Entry id is {$entryId}
" );

    // Sub-nodes can be referenced as member variables and looped over
    foreach( $entry->configuration as $configuration ) {

        $configurationId = $configuration['id'];
        echo( "Configuration id is {$configurationId}
" );

        foreach( $configuration->logical as $logical ) {

            // You can string the methods together like this:
            $factName = $logical->fact[0]['name'];
            echo( "Logical fact name = $factName" );
        }

    }

}

?>

According to the updated question, the issue though seems to be related to namespaces.

You could strip those definitions out...

Whilst this probably isn't the recommended way round it (registering the namespaces is probably the way to go, but they don't appear to have valid URIs, so that may not be an option).

My example becomes:

<?

$content = '<?xml version=\'1.0\' encoding=\'UTF-8\'?>
<nvd xmlns:scap-core="http//0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:patch="http//patch/0.1" xmlns="http//obj/0.1" xmlns:lang="http//lang/2.0" xmlns:cvss="http//cvss-v2/0.2" xmlns:object="http//object/0.4" nvd_xml_version="2.0" pub_date="2014-02-25T10:00:00" xsi:schemaLocation="http//patch/0.1 http//schema/patch_0.1.xsd http//0.1 http//schema/scap-core_0.1.xsd http//obj/0.1 http//schema/nvd-cve-feed_2.0.xsd">
  <entry id="0528">
    <object:configuration id="site.com/">
      <lang:logical-test negate="false" operator="OR">
        <lang:fact-ref name="version:2.6.0"/>
        <lang:fact-ref name="version:2.6.1"/>
        <lang:fact-ref name="version:2.6.2"/>
        <lang:fact-ref name="version:2.6.3"/>
      </lang:logical-test>
    </object:configuration>
    <object:list>
      <object:product>version:2.6.3</object:product>
      <object:product>version:2.6.0</object:product>
      <object:product>version:2.6.1</object:product>
      <object:product>version:2.6.2</object:product>
    </object:list>
    <object:id>0528</object:id>
    <object:published-datetime>2014-02-17T11:55:04.787-05:00</object:published-datetime>
    <object:last-modified-datetime>2014-02-21T09:14:10.780-05:00</object:last-modified-datetime>
    <object:cwe id="264"/>
  </entry>
</nvd>';


$content = preg_replace('/xmlns[^=]*="[^"]*"/i', '', $content);

// Gets rid of all namespace references
$content = preg_replace('/[a-zA-Z]+:([a-zA-Z]+[\W=>])/', '$1', $content);

$xml = new SimpleXMLElement($content);

foreach ($xml as $entry){

    // attributes can be referenced as array elements
    $entryId = $entry['id'];


    echo( "Entry id is {$entryId}
" );

    // Sub-nodes can be referenced as member variables and looped over
    foreach( $entry->configuration as $configuration ) {

        $configurationId = $configuration['id'];
        echo( "Configuration id is {$configurationId}
" );

        // Note for hyphenated nodes you need to wrap in quotes and curlies
        foreach( $configuration->{'logical-test'} as $logical ) {

            $testOperator = $logical['operator'];
            echo( "Test Operator = $testOperator
" );

            // You can string the methods together like this:
            $factName = $logical->{'fact-ref'}[0]['name'];
            echo( "Logical fact name = $factName
" );
        }

    }

}

?>

Which outputs:

Entry id is 0528
Configuration id is site.com/
Test Operator = OR
Logical fact name = version:2.6.0

Note that in order to access the nodes with hyphens in their names you need to wrap in curlies and quotes. E.g. $logical->{'fact-ref'}