手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表Tag:simplexml

php simplexmlElement 操作xml的命名空间

这是今天中午发生的事情,有人在群里求助,比如xml中如果标记是<xx:xxxx>content</xx:xxxx>这样的情况下,取不到 xx:xxxx 为下标的值。
看了这个问题,第一个反应就是namespace的关系,但我从来没有使用simplexml操作过namespace,于是就翻开手册查了一下资料,问题并没有解决,最终是通过google解决了该问题。

提问题的朋友贴出了数据源,来自于:http://code.google.com/intl/zh-CN/apis/contacts/docs/3.0/developers_guide_protocol.html#retrieving_without_query,数据结构大致如下:

XML/HTML代码
  1. <feed xmlns='http://www.w3.org/2005/Atom'      xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'      xmlns:gContact='http://schemas.google.com/contact/2008'      xmlns:batch='http://schemas.google.com/gdata/batch'      xmlns:gd='http://schemas.google.com/g/2005'      gd:etag='W/"CUMBRHo_fip7ImA9WxRbGU0."'>      
  2.     <id>liz@gmail.com</id>      
  3.     <updated>2008-12-10T10:04:15.446Z</updated>      
  4.     <category scheme='http://schemas.google.com/g/2005#kind'      term='http://schemas.google.com/contact/2008#contact' />      
  5.     <title>Elizabeth Bennet's Contacts</title>      
  6.     <link rel='http://schemas.google.com/g/2005#feed'      type='application/atom+xml'      href='https://www.google.com/m8/feeds/contacts/liz%40gmail.com/full' />      
  7.     <link rel='http://schemas.google.com/g/2005#post'      type='application/atom+xml'      href='https://www.google.com/m8/feeds/contacts/liz%40gmail.com/full' />      
  8.     <link rel='http://schemas.google.com/g/2005#batch'      type='application/atom+xml'      href='https://www.google.com/m8/feeds/contacts/liz%40gmail.com/full/batch' />      
  9.     <link rel='self' type='application/atom+xml'      href='https://www.google.com/m8/feeds/contacts/liz%40gmail.com/full?max-results=25' />      
  10.     <author>        
  11.         <name>Elizabeth Bennet</name>        
  12.         <email>liz@gmail.com</email>      
  13.     </author>      
  14.     <generator version='1.0' uri='http://www.google.com/m8/feeds'>      Contacts    </generator>      
  15.     <openSearch:totalResults>1</openSearch:totalResults>      
  16.     <openSearch:startIndex>1</openSearch:startIndex>      
  17.     <openSearch:itemsPerPage>25</openSearch:itemsPerPage>      
  18.     <entry gd:etag='"Qn04eTVSLyp7ImA9WxRbGEUORAQ."'>        
  19.         <id>        http://www.google.com/m8/feeds/contacts/liz%40gmail.com/base/c9012de      </id>        
  20.         <updated>2008-12-10T04:45:03.331Z</updated>        
  21.         <app:edited xmlns:app='http://www.w3.org/2007/app'>2008-12-10T04:45:03.331Z</app:edited>        
  22.         <category scheme='http://schemas.google.com/g/2005#kind'        term='http://schemas.google.com/contact/2008#contact' />        
  23.         <title>Fitzwilliam Darcy</title>        
  24.         <gd:name>          
  25.             <gd:fullName>Fitzwilliam Darcy</gd:fullName>        
  26.         </gd:name>        
  27.         <link rel='http://schemas.google.com/contacts/2008/rel#photo' type='image/*'        href='https://www.google.com/m8/feeds/photos/media/liz%40gmail.com/c9012de'        gd:etag='"KTlcZWs1bCp7ImBBPV43VUV4LXEZCXERZAc."' />        
  28.         <link rel='self' type='application/atom+xml'        href='https://www.google.com/m8/feeds/contacts/liz%40gmail.com/full/c9012de' />        
  29.         <link rel='edit' type='application/atom+xml'        href='https://www.google.com/m8/feeds/contacts/liz%40gmail.com/full/c9012de' />        
  30.         <gd:phoneNumber rel='http://schemas.google.com/g/2005#home'        primary='true'>        456      </gd:phoneNumber>        
  31.         <gd:extendedProperty name='pet' value='hamster' />        
  32.         <gContact:groupMembershipInfo deleted='false'        href='http://www.google.com/m8/feeds/groups/liz%40gmail.com/base/270f' />      
  33.     </entry>    
  34. </feed>  

这个结构在上面的地址里有,这个是我格式化过的XML数据,现在要取得类似于“<gd:phoneNumber rel='http://schemas.google.com/g/2005#home'        primary='true'>        456      </gd:phoneNumber> ”中的值。

最终代码如下:

PHP代码
  1. $x = new SimpleXmlElement($str);  
  2. foreach($x->entry as $t){  
  3.     echo $t->id . "<br >";  
  4.     echo $t->updated . "<br />";  
  5.     $namespaces = $t->getNameSpaces(true);  
  6.     $gd = $t->children($namespaces['gd']);   
  7.     echo $gd->phoneNumber;  
  8. }  

当然,如果不象上面这样写,也可以写成这样:

PHP代码
  1. $x = new SimpleXmlElement($str);  
  2. foreach($x->entry as $t){  
  3.     echo $t->id . "<br >";  
  4.     echo $t->updated . "<br />";  
  5.     //$namespaces = $t->getNameSpaces(true);  
  6.     //注意这里与上面一段的区别  
  7.     $gd = $t->children('http://schemas.google.com/g/2005');   
  8.     echo $gd->phoneNumber;  
  9. }  

只是象第二种写法就属于硬编码了,这样不太好,万一哪天有变化,还得再更改N多代码。
问题接踵而来,比如象下面这段:

XML/HTML代码
  1. <event:event>   
  2. <event:sessionKey></event:sessionKey>   
  3. <event:sessionName>Learn QB in Minutes</event:sessionName>   
  4. <event:sessionType>9</event:sessionType>   
  5. <event:hostWebExID></event:hostWebExID>   
  6. <event:startDate>02/12/2009</event:startDate>   
  7. <event:endDate>02/12/2009</event:endDate>   
  8. <event:timeZoneID>11</event:timeZoneID>   
  9. <event:duration>30</event:duration>   
  10. <event:description></event:description>   
  11. <event:status>NOT_INPROGRESS</event:status>   
  12. <event:panelists></event:panelists>   
  13. <event:listStatus>PUBLIC</event:listStatus>   
  14. </event:event>  

这种非标准的XML,没有定义命名空间,怎么办?在这种情况下,其实SimpleXmlElement就已经直接可以解决了,但是会报warnging,因为他认为event这个命名空间不存在。
解决方法是:

PHP代码
  1. $xml = @new SimpleXmlElement($str);//在前面加@抑止错误。  
  2. echo "<pre>";  
  3. print_r($xml);  

目前看来,这种解决方法比较好。

Tags: php, simplexml, xml, namespace

simplexml xpath

SimpleXmlElement 在我们用的时候好象很多都是直接使用simplexml_load_string或者load_file。但事实上,SimpleXmlElement功能很强大,只是我们很多时候都忽略了?大多数人还在使用xml_create等函数?

SimpleXmlElement中最让人用的舒服的恐怕就是这个xpath了。例如这个官方的例子:

PHP代码
  1. <?php  
  2. $string = <<<XML  
  3. <a>  
  4.  <b>  
  5.   <c>text</c>  
  6.   <c>stuff</c>  
  7.  </b>  
  8.  <d>  
  9.   <c>code</c>  
  10.  </d>  
  11. </a>  
  12. XML;  
  13.   
  14. $xml = new SimpleXMLElement($string);  
  15.   
  16. /* Search for <a><b><c> */  
  17. $result = $xml->xpath('/a/b/c');  
  18.   
  19. while(list( , $node) = each($result)) {  
  20.     echo '/a/b/c: ',$node,"\n";  
  21. }  
  22.   
  23. /* Relative paths also work... */  
  24. $result = $xml->xpath('b/c');  
  25.   
  26. while(list( , $node) = each($result)) {  
  27.     echo 'b/c: ',$node,"\n";  
  28. }  
  29. ?>  
这个例子输出是:
XML/HTML代码
  1. /a/b/c: text  
  2. /a/b/c: stuff  
  3. b/c: text  
  4. b/c: stuff  

看看,是不是很方便?对于某个XML很大的情况就比较值得这样使用了。

Tags: simplexml, xpath

PHP里simplexml_load_string函数一个容易犯晕的地方

以下内容均来自老王。说实话,simplexml的这些问题我以前遇到过,而且还是非常强烈的遇到了。
那时候是08年的事了,项目中与SOAP在交互,返回的都是XML,所以就直接采用了simplexml_load_string了。这时候就会遇到这种问题,比如我拉一个列表,但会有三种情况:1、没数据,2、1条数据,3、正常数据
1、没数据的时候,返回一个空的simplexml Object,
2、一条数据的时候,返回的也是一个simplexml Object,结果集成了这个object的元素
3、数据列表,这时候返回的却是一个Array,每一个元素是simplexml Object,等同于2。
后来我是没办法,就多写了一个函数判断,如果是object,并且不为空,直接把object强制转为array,因为,如果是空的simplexml Object,强制转的话,还是Object,转不了。。。

当时还有一个可恨的事情,我以前可能介绍过,xml在返回的时候,他的形式可能是这样的<test-name>gouki</test-name>,在返回这样的形式时,生成object时,却是test_name,在没有print_r出来时,我死活搞不定。。。后来才发现这个问题,郁闷啊

好了,说了半天,该说说老王的内容了:
这个问题遇到好几次了,今天翻看以前代码的时候看到,便记下来,先用一段代码重现一下问题:

PHP代码
  1. <pre>  
  2. <?php  
  3. $string = <<<EOF  
  4. <data>  
  5. <foo><bar>hello</bar></foo>  
  6. <foo><bar>world</bar></foo>  
  7. </data>  
  8. EOF;  
  9.   
  10. $data = simplexml_load_string($string);  
  11.   
  12. print_r($data);  
  13. print_r($data->foo);  
  14. ?>  
  15. </pre>   

乍一看,结果很让人费解:

XML/HTML代码
  1. SimpleXMLElement Object  
  2. (  
  3.     [foo] => Array  
  4.         (  
  5.             [0] => SimpleXMLElement Object  
  6.                 (  
  7.                     [bar] => hello  
  8.                 )  
  9.             [1] => SimpleXMLElement Object  
  10.                 (  
  11.                     [bar] => world  
  12.                 )  
  13.         )  
  14. )  
  15. SimpleXMLElement Object  
  16. (  
  17.     [bar] => hello  
  18. )  

明明print_r显示foo是一个有两个bar元素的数组,但是最后却仅仅显示了一个bar元素!

原因其实很简单,在如上所示simplexml_load_string的结果里,foo并不是数组,而是一个迭代对象!

可以这样确认:

PHP代码
  1. foreach ($data->foo as $v) print_r($v);  
  2. foreach ($data->children() as $v) print_r($v);  
看来,print_r或者var_dump之类的表象并不完全可信,自己多留心吧。
原文来自:http://hi.baidu.com/thinkinginlamp/blog/item/9dbb15ce7a621632b700c86a.html

Tags: simplexml, 老王

simplexml简单测试

simplexml函数是PHP5推出的一个新的类库,可以让你很方便的操作XML,对大多数人而言,最常用的应该是simplexml_load_file和simple_load_string两种了。

但是在使用中总会有一点问题,于是做了简单的一些测试。

建立了四个文件,两个GBK,两个UTF8,

两个GBK的文件内容分别如下:

XML/HTML代码
  1. <?xml version="1.0" encoding="gbk" ?>  
  2. <test>  
  3.     <test1>this is a test中文</test1>  
  4. </test>  

XML/HTML代码
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <test>  
  3.     <test1>this is a test中文</test1>  
  4. </test>  
正如你们想的那样,UTF8的文件也是这些内容。

然后开始使用 simplexml_load_file进行测试:

PHP代码
  1. <?php  
  2. $xmlFile = '1.txt';  
  3.   
  4. $xml = @simplexml_load_file( $xmlFile );  
  5. if ( $xml === false ){  
  6.     echo'failed' );  
  7. }else{  
  8.     echo '<pre>';  
  9.     print_r( $xml );  
  10.     echo '</pre>';  
  11. }  
  12.   
  13. ?>  
然后,你会发现什么?

1、如果xml的encoding与文件类型不符,立刻报错
2、simplexml可以处理gbk的XML,即文件内容和encoding都为gbk(ANSI格式)
3、不管文件内容是什么,处理完了,都是UTF8.

over,测试完毕


其实想这个测试还有另外一个原因,因为thinkPHP的模版引擎的自定义扩展是采用XML来实现的,以前很多朋友在扩展的时候都会报错,那时候,我们的提示是:请使用 UTF8格式创建XML,现在,我们又可以提示:随便你想怎么创建,只要您的文件格式和encoding一致就行。

 

Tags: simplexml, test, utf-8, gbk