将PHP关联数组传递到XML并从XML中传回

18

有没有一种简单的方法将PHP关联数组编组为XML并从XML解组?例如,我有以下数组:

$items = array("1", "2",
    array(
        "item3.1" => "3.1",
        "item3.2" => "3.2"
        "isawesome" => true
    )
);

我该如何尽可能少地将其转换为类似以下XML的内容,然后再转回来?

<items>
    <item>1</item>
    <item>2</item>
    <item>
        <item3_1>3.1</item3_1>
        <item3_2>3.2</item3_2>
        <isawesome>true</isawesome>
    </item>
</items>

我并不介意稍微改变一下数组结构,或者生成的XML与上面的示例有所不同。我一直在尝试使用PHP的XMLReaderXMLWriter,但是文档非常贫乏,因此我编写的代码看起来与我想象中的完全不同:

$xml = SomeXMLWriter::writeArrayToXml($items);
$array = SomeXMLWriter::writeXmlToArray($xml);

获取 PHP 数组的基本、原始的 XML 转储,真的必须比这更困难吗?而不编写自己的自定义类?

我尝试避免使用 PEAR。除了我曾经与它有过的配置问题之外,我从来没有坚持使用过其中任何一个软件包。

15个回答

1
这是在Ángel López的回答基础上进行的构建。增加了属性支持。如果一个元素有属性,请使用@作为前缀,并将实际元素内容引用为空字符串键。
/**
 * Build an XML Data Set
 *
 * @param array $data Associative Array containing values to be parsed into an XML Data Set(s)
 * @param string $startElement Root Opening Tag, default fx_request
 * @param string $xml_version XML Version, default 1.0
 * @param string $xml_encoding XML Encoding, default UTF-8
 * @return string XML String containig values
 * @return mixed Boolean false on failure, string XML result on success
 */
function arrayToXML($data, $startElement = 'fx_request', $xml_version = '1.0', $xml_encoding = 'UTF-8'){
  if(!is_array($data)){
    $err = 'Invalid variable type supplied, expected array not found on line '.__LINE__." in Class: ".__CLASS__." Method: ".__METHOD__;
    trigger_error($err);
    //if($this->_debug) echo $err;
    return false; //return false error occurred
  }
  $xml = new XmlWriter();
  $xml->openMemory();
  $xml->startDocument($xml_version, $xml_encoding);
  $xml->startElement($startElement);

  /**
   * Write keys in $data prefixed with @ as XML attributes, if $data is an array. When an @ prefixed key is found, a '' key is expected to indicate the element itself.
   * @param object $xml XMLWriter Object
   * @param array $data with attributes filtered out
   */
  function writeAttr(XMLWriter $xml, $data) {
    if(is_array($data)) {
      $nonAttributes = array();
      foreach($data as $key => $val) {
        //handle an attribute with elements
        if($key[0] == '@') {
          $xml->writeAttribute(substr($key, 1), $val);
        } else if($key == '') {
          if(is_array($val)) $nonAttributes = $val;
          else $xml->text("$val");
        }

        //ignore normal elements
        else $nonAttributes[$key] = $val;
      }
      return $nonAttributes;
    }
    else return $data;
  }

  /**
   * Write XML as per Associative Array
   * @param object $xml XMLWriter Object
   * @param array $data Associative Data Array
   */
  function writeEl(XMLWriter $xml, $data) {
    foreach($data as $key => $value) {
      if(is_array($value) && isset($value[0])) { //numeric array
        foreach($value as $itemValue){
          if(is_array($itemValue)) {
            $xml->startElement($key);
            $itemValue = writeAttr($xml, $itemValue);
            writeEl($xml, $itemValue);
            $xml->endElement();
          } else {
            $itemValue = writeAttr($xml, $itemValue);
            $xml->writeElement($key, "$itemValue");
          }
        }
      } else if(is_array($value)) { //associative array
        $xml->startElement($key);
        $value = writeAttr($xml, $value);
        writeEl($xml, $value);
        $xml->endElement();
      } else { //scalar
        $value = writeAttr($xml, $value);
        $xml->writeElement($key, "$value");
      }
    }
  }
  writeEl($xml, $data);

  $xml->endElement();//write end element
  //returns the XML results
  return $xml->outputMemory(true);
}

所以你可以将这个转换成:

$mArray["invitations"]["user"][0]["@name"] = "paco";
$mArray["invitations"]["user"][0][""]["amigos"][0] = 82;
$mArray["invitations"]["user"][0][""]["amigos"][1] = 29;
$mArray["invitations"]["user"][0][""]["amigos"][2] = 6;

$mArray["invitations"]["user"][1]["@name"] = "jose";
$mArray["invitations"]["user"][1][""]["amigos"][0] = 43;
$mArray["invitations"]["user"][1][""]["amigos"][1]["tuyos"] = 32;
$mArray["invitations"]["user"][1][""]["amigos"][1]["mios"] = 79;
$mArray["invitations"]["user"][1][""]["amigos"][2] = 11;

$mArray["invitations"]["user"][2]["@name"] = "luis";
$mArray["invitations"]["user"][2][""]["amigos"][0] = 65;

into this xml:

<invitations>
  <user name="paco">
    <amigos>82</amigos>
    <amigos>29</amigos>
    <amigos>6</amigos>
  </user>
  <user name="jose">
    <amigos>43</amigos>
    <amigos>
      <tuyos>32</tuyos>
      <mios>79</mios>
    </amigos>
    <amigos>11</amigos>
  </user>
  <user name="luis">
    <amigos>65</amigos>
  </user>
</invitations>

感谢Ángel。

很酷,但如果你像这样创建关联数组:array('123' => 'asdf'),它就无法工作了。 可能你应该检查每个键是否为数字。 - jmarceli

1

我同意这是 PHP 文档中有所疏漏的一个领域,但对我来说,我一直使用 SimpleXML 与 xml2Array 函数混合使用。从 simpleXML 获取的 XML 并不难以通过像 print_r 这样的转储函数进行导航。


0

从xml字符串获取关联数组最简单的方法:

<?
$data_array = (array) simplexml_load_string($xml_string);
?>

0
/**
 * Write XML as per Associative Array
 * @param object $xml XMLWriter Object
 * @param array $data Associative Data Array
 */
function writeXmlRecursive(XMLWriter $xml, $data){
    foreach($data as $key => $value){
        if (is_array($value) && isset($value[0])){
            $xml->startElement($key);
            foreach($value as $itemValue){

                if(is_array($itemValue)){
                    writeXmlRecursive($xml, $itemValue);
                }
                else
                {
                    $xml->writeElement($key, $itemValue."");
                }
            }
            $xml->endElement();

        }else if(is_array($value)){
            $xml->startElement($key);
            writeXmlRecursive($xml, $value);
            $xml->endElement();
            continue;
        }

        if (!is_array($value)){
            $xml->writeElement($key, $value."");
        }
    }
}

这是最终版本,可以从四个嵌套级别的数组中获取我想要的内容。

<items>
<item>
  <id_site>59332</id_site>
  <id>33</id>
  <code>196429985</code>
  <tombid>23</tombid>
  <tombcode>196429985</tombcode>
  <religion></religion>
  <lastname>lastname</lastname>
  <firstname>name</firstname>
  <patronymicname>patronymicname</patronymicname>
  <sex>1</sex>
  <birthday>2</birthday>
  <birthmonth>4</birthmonth>
  <birthyear>1946</birthyear>
  <deathday>13</deathday>
  <deathmonth>5</deathmonth>
  <deathyear>2006</deathyear>
  <s_comments></s_comments>
  <graveyard>17446</graveyard>
  <latitude></latitude>
  <longitude></longitude>
  <images>
   <image>
    <siteId>52225</siteId>
    <fileId>62</fileId>
    <prefix>0</prefix>
    <path>path</path>
   </image>
   <image>
    <siteId>52226</siteId>
    <fileId>63</fileId>
    <prefix>0</prefix>
    <path>path</path>
   </image>
  </images>
 </item>
<items>

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接