三行 xml2array
<?php
$xml = simplexml_load_string($xmlstring);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
?>
太棒了!
三行 xml2array
<?php
$xml = simplexml_load_string($xmlstring);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
?>
太棒了!
在 $_SESSION 中存储 SimpleXMLElement 值不起作用。将结果保存为对象或对象的单个元素会导致可怕的“警告:session_start() [function.session-start]:节点不再存在”错误。
例如,这不起作用
$xml = new SimpleXMLElement($page);
$country = $xml->Response->Placemark->AddressDetails->Country->CountryNameCode;
$_SESSION['country'] = $country;
这将起作用
$_SESSION['country'] = (string) $country;
这是一个递归函数,它将把给定的 SimpleXMLElement 对象转换为数组,保留命名空间和属性。
<?php
function xmlObjToArr($obj) {
$namespace = $obj->getDocNamespaces(true);
$namespace[NULL] = NULL;
$children = array();
$attributes = array();
$name = strtolower((string)$obj->getName());
$text = trim((string)$obj);
if( strlen($text) <= 0 ) {
$text = NULL;
}
// 获取所有命名空间的信息
if(is_object($obj)) {
foreach( $namespace as $ns=>$nsUrl ) {
// 属性
$objAttributes = $obj->attributes($ns, true);
foreach( $objAttributes as $attributeName => $attributeValue ) {
$attribName = strtolower(trim((string)$attributeName));
$attribVal = trim((string)$attributeValue);
if (!empty($ns)) {
$attribName = $ns . ':' . $attribName;
}
$attributes[$attribName] = $attribVal;
}
// 子节点
$objChildren = $obj->children($ns, true);
foreach( $objChildren as $childName=>$child ) {
$childName = strtolower((string)$childName);
if( !empty($ns) ) {
$childName = $ns.':'.$childName;
}
$children[$childName][] = xmlObjToArr($child);
}
}
}
return array(
'name'=>$name,
'text'=>$text,
'attributes'=>$attributes,
'children'=>$children
);
}
?>
当使用 SimpleXML 从 XML 对象中获取 double、float 或 int 值以进行数学运算(+ * - /)时,操作过程中可能会出现错误。这是因为 SimpleXML 将所有内容都返回为对象。
例如;
<?php
$name = "somestring";
$size = 11.45;
$xml = '
<xml>
<name>somestring</name>
<size>11.45</size>
</xml>';
$xmlget = simplexml_load_string($xml)
echo $xml->size*2; // 20 错误
// ($xml->size 是一个对象 (int)11 和 (45) )
// 正确的
echo $size*2; // 22.90
echo (float)$size*2; // 22.90
?>
如果你尝试使用此方法加载一个 XML 文件,但 CDATA 部分未加载,这是因为你需要以这种方式进行操作
$xml = simplexml_load_file($this->filename, 'SimpleXMLElement', LIBXML_NOCDATA);
这会将 CDATA 转换为返回对象中的字符串。
为了补充其他人的说法,你不能直接将 $_GET 或 $_POST 值放入变量,然后使用 SimpleXML 放入属性中。你必须先将其转换为整数。
这将不起作用
<?php
$page_id = $_GET['id'];
echo $xml->page[$page_id]
?>
你将得到类似的内容
注意:尝试获取非对象属性 /Applications/MAMP/htdocs/mysite/index.php 第 10 行
但是,这将起作用,并且比使用 (string) 或其他方法更简单。
<?php
$page_id = intval($_GET['id']);
echo $xml->page[$page_id]
?>
简单意味着简单。如果你知道结构,并且只想获取标签的值
<?php
$xml = simplexml_load_file($xmlfile);
print $xml->City->Street->Address->HouseColor;
?>
警告,数字可能会以字符串的形式出现,空元素如 <HouseColor></HouseColor> 会以数组 (0) 的形式出现
这里有两个快速且简陋的函数,它们使用 SimpleXML 来检测 feed xml 是 RSS 还是 ATOM
<?php
function is_rss($feedxml) {
@$feed = new SimpleXMLElement($feedxml);
if ($feed->channel->item) {
return true;
} else {
return false;
}
}
function is_atom($feedxml) {
@$feed = new SimpleXMLElement($feedxml);
if ($feed->entry) {
return true;
} else {
return false;
}
}
?>
这些函数接受完整的文本 feed(例如,通过 cURL 获取),并根据结果返回 true 或 false。
用于简单 SAX 读取大型 XML 的包装器 XMLReader 类
https://github.com/dkrnl/SimpleXMLReader
用法示例:http://github.com/dkrnl/SimpleXMLReader/blob/master/examples/example1.php
<?php
/**
* 简单 XML 阅读器
*
* @license 公共领域
* @author Dmitry Pyatkov(aka dkrnl) <[email protected]>
* @url http://github.com/dkrnl/SimpleXMLReader
*/
class SimpleXMLReader extends XMLReader
{
/**
* 回调函数
*
* @var array
*/
protected $callback = array();
/**
* 添加节点回调函数
*
* @param string $name
* @param callback $callback
* @param integer $nodeType
* @return SimpleXMLReader
*/
public function registerCallback($name, $callback, $nodeType = XMLREADER::ELEMENT)
{
if (isset($this->callback[$nodeType][$name])) {
throw new Exception("回调函数 $name($nodeType) 已存在。");
}
if (!is_callable($callback)) {
throw new Exception("解析器回调函数 $name($nodeType) 已存在。");
}
$this->callback[$nodeType][$name] = $callback;
return $this;
}
/**
* 移除节点回调函数
*
* @param string $name
* @param integer $nodeType
* @return SimpleXMLReader
*/
public function unRegisterCallback($name, $nodeType = XMLREADER::ELEMENT)
{
if (!isset($this->callback[$nodeType][$name])) {
throw new Exception("未知的解析器回调函数 $name($nodeType)。");
}
unset($this->callback[$nodeType][$name]);
return $this;
}
/**
* 运行解析器
*
* @return void
*/
public function parse()
{
if (empty($this->callback)) {
throw new Exception("解析器回调函数为空。");
}
$continue = true;
while ($continue && $this->read()) {
if (isset($this->callback[$this->nodeType][$this->name])) {
$continue = call_user_func($this->callback[$this->nodeType][$this->name], $this);
}
}
}
/**
* 在当前节点上运行 XPath 查询
*
* @param string $path
* @param string $version
* @param string $encoding
* @return array(SimpleXMLElement)
*/
public function expandXpath($path, $version = "1.0", $encoding = "UTF-8")
{
return $this->expandSimpleXml($version, $encoding)->xpath($path);
}
/**
* 将当前节点扩展为字符串
*
* @param string $version
* @param string $encoding
* @return SimpleXMLElement
*/
public function expandString($version = "1.0", $encoding = "UTF-8")
{
return $this->expandSimpleXml($version, $encoding)->asXML();
}
/**
* 将当前节点扩展为 SimpleXMLElement
*
* @param string $version
* @param string $encoding
* @param string $className
* @return SimpleXMLElement
*/
public function expandSimpleXml($version = "1.0", $encoding = "UTF-8", $className = null)
{
$element = $this->expand();
$document = new DomDocument($version, $encoding);
$node = $document->importNode($element, true);
$document->appendChild($node);
return simplexml_import_dom($node, $className);
}
/**
* 将当前节点扩展为 DomDocument
*
* @param string $version
* @param string $encoding
* @return DomDocument
*/
public function expandDomDocument($version = "1.0", $encoding = "UTF-8")
{
$element = $this->expand();
$document = new DomDocument($version, $encoding);
$node = $document->importNode($element, true);
$document->appendChild($node);
return $document;
}
}
?>
XML 文件和 PHP 数组之间最大的区别在于,在 XML 文件中,元素的名称即使是兄弟节点也可以相同,例如 "<pa><ch /><ch /><ch /></pa>",而在 PHP 数组中,键必须不同。
我认为 svdmeer 开发的数组结构适合 XML,而且很适合。
这里是一个从 XML 文件转换来的数组示例
array(
"@tag"=>"name",
"@attr"=>array(
"id"=>"1","class"=>"2")
"@text"=>"some text",
)
或者如果它有子节点,可以是
array(
"@tag"=>"name",
"@attr"=>array(
"id"=>"1","class"=>"2")
"@items"=>array(
0=>array(
"@tag"=>"name","@text"=>"some text"
)
)
另外,我编写了一个可以将该数组转换回 XML 的函数。
<?php
function array2XML($arr,$root) {
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"utf-8\" ?><{$root}></{$root}>");
$f = create_function('$f,$c,$a','
foreach($a as $v) {
if(isset($v["@text"])) {
$ch = $c->addChild($v["@tag"],$v["@text"]);
} else {
$ch = $c->addChild($v["@tag"]);
if(isset($v["@items"])) {
$f($f,$ch,$v["@items"]);
}
}
if(isset($v["@attr"])) {
foreach($v["@attr"] as $attr => $val) {
$ch->addAttribute($attr,$val);
}
}
}');
$f($f,$xml,$arr);
return $xml->asXML();
}
?>
以下是一种快速方法,可以使用每个节点值的路径作为键,将 SimpleXML 中的节点值转储到数组中。这些路径与例如 DOMXPath 兼容。当需要在外部更新值(即在不知道基础 XML 的代码中)时,我会使用它。然后,我使用 DOMXPath 查找包含原始值的节点并更新它。
<?php
function XMLToArrayFlat($xml, &$return, $path='', $root=false)
{
$children = array();
if ($xml instanceof SimpleXMLElement) {
$children = $xml->children();
if ($root){ // we're at root
$path .= '/'.$xml->getName();
}
}
if ( count($children) == 0 ){
$return[$path] = (string)$xml;
return;
}
$seen=array();
foreach ($children as $child => $value) {
$childname = ($child instanceof SimpleXMLElement)?$child->getName():$child;
if ( !isset($seen[$childname])){
$seen[$childname]=0;
}
$seen[$childname]++;
XMLToArrayFlat($value, $return, $path.'/'.$child.'['.$seen[$childname].']');
}
}
?>
使用方法
<?php
$xml = simplexml_load_string(...some xml string...);
$xmlarray = array(); // 此数组将保存扁平化后的数据
XMLToArrayFlat($xml, $xmlarray, '', true);
?>
您也可以将多个文件拉入一个数组中
<?php
foreach($files as $file){
$xml = simplexml_load_file($file);
XMLToArrayFlat($xml, $xmlarray, $file.':', true);
}
?>
相应的文件名/路径将作为前缀添加到每个键中。
以下是我写的一个将关联数组转换为 XML 的函数。它也适用于多维数组。
<?php
function assocArrayToXML($root_element_name,$ar)
{
$xml = new SimpleXMLElement("<?xml version=\"1.0\"?><{$root_element_name}></{$root_element_name}>");
$f = create_function('$f,$c,$a','
foreach($a as $k=>$v) {
if(is_array($v)) {
$ch=$c->addChild($k);
$f($f,$ch,$v);
} else {
$c->addChild($k,$v);
}
}');
$f($f,$xml,$ar);
return $xml->asXML();
}
?>
使用 XML 在 PHP 中进行动态 SQL
test.xml
<?xml version="1.0" encoding="UTF-8"?>
<sql>
<statement>
SELECT * FROM USERS
<call criteria="byId">WHERE id = %d</call>
<call criteria="byUsername">WHERE username = "%s"</call>;
</statement>
</sql>
index.php
<?php
function callMe($param) {
$search = array('byUsername' => 'dynsql');
if (isset($search[$param[1]])) {
return sprintf($param[2], $search[$param[1]]);
}
return "";
}
$xml = simplexml_load_file("test.xml");
$string = $xml->statement->asXML();
$string = preg_replace_callback('/<call criteria="(\w+)">(.*?)<\/call>/', 'callMe', $string);
$node = simplexml_load_string($string);
echo $node;
?>
当然,此示例可以 [在您的代码中] 进行改进。
我在使用 simplexml 从 XML 文件中读取节点时遇到了问题。它总是返回一个 SimpleXML 对象,而不是节点内的文本。
示例
<?xml version="1.0" encoding="UTF-8"?>
<Test>
<Id>123</Id>
</Test>
将此 XML 读取到名为 $xml 的变量中,然后执行以下操作
<?php
$myId = $xml->Id;
?>
没有在 $myId 中返回 123,而是得到了一个 SimpleXMLElement 对象。
解决方案很简单,只要您知道它。使用显式字符串转换。
<?php
$myId = (string)$xml->Id;
?>
两行 xml2array
<?php
$xml = simplexml_load_string($xmlstring);
$array = (array) $xml;
?>