将 PHP 关联数组传入和传出 XML

Posted

技术标签:

【中文标题】将 PHP 关联数组传入和传出 XML【英文标题】:Passing PHP associative arrays to and from XML 【发布时间】:2010-09-11 02:11:33 【问题描述】:

有没有一种简单的方法可以将 php 关联数组与 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 的 XMLReader 和 XMLWriter,但是文档太差了,因此我生成的代码看起来不像我认为的那样:

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

在不编写我自己的自定义类的情况下获得 PHP 数组的基本原始 XML 转储真的比这更难吗?

我尽量避免使用 PEAR。除了我在使用它时遇到的配置问题之外,我从来没有使用过我曾经使用过的任何软件包。

【问题讨论】:

【参考方案1】:

SimpleXML 非常适合您使用。

【讨论】:

【参考方案2】:

对于那些不使用 PEAR 包但已安装 PHP5 的人。这对我有用:

/**
 * Build A 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
 */
public function buildXMLData($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 XML as per Associative Array
     * @param object $xml XMLWriter Object
     * @param array $data Associative Data Array
     */
     function write(XMLWriter $xml, $data) 
         foreach($data as $key => $value) 
             if(is_array($value)) 
                 $xml->startElement($key);
                 write($xml, $value);
                 $xml->endElement();
                 continue;
             
             $xml->writeElement($key, $value);
         
     
     write($xml, $data);

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

【讨论】:

如果你的数据中有非关联数组(或者更确切地说,数组键中有数字),添加一个'if (is_numeric($key)) $key = "item";'在 foreach 块的开头(在 is_array 之前)就可以了。 为了也能处理数值数组,添加$fKey = is_numeric($key) ? 'numericValue' : $key; before if(is_array($value)) 语句,并在foreach 语句的其余部分使用$fKey 哦@VassilisGr,我在那里做了类似的事情:if(is_numeric($key)) $key = 'node'; 并将function write 移到外面,你不能声明两次相同的函数,但@Conrad 现在会这样做。 (该死,我现在看到@disq 评论哈哈)【参考方案3】:

我也遇到过一些同样的问题,所以我创建了两个类:

bXml

扩展 SimpleXml 并纠正其存在的一些问题的类。就像无法添加 CData 节点或 Comment 节点一样。我还添加了一些附加功能,例如使用 php 流功能添加子节点 $oXml-&gt;AddChild("file:///user/data.xml") 或添加 XML 字符串子节点,如 $oXml-&gt;AddChild("&lt;more&gt;&lt;xml&gt;yes&lt;/xml&gt;&lt;/more&gt;");,但基本上我只是想修复 simpleXML 问题。

bArray

我扩展了 ArrayObject 类,以便所有数组功能都可以面向对象且一致,因此您无需记住 array_walk 通过引用对数组进行操作,而 array_filter 通过值对数组进行操作。因此,您可以执行$oArray-&gt;flip()-&gt;Reverse()-&gt;Walk(/*callback*/); 之类的操作,然后仍以您通常希望$oArray[key] 的方式访问该值。

这两种方法都将自身输出为数组和 Xml,因此您可以在它们之间无缝跳转。所以你可以$oXml-&gt;AsArray();$oArray-&gt;AsXml(); 我发现这样做比在array2xml 或xml2array 方法之间不断地来回传递东西更容易。

http://code.google.com/p/blibrary/source

这两个类都可以被覆盖以创建您选择的自定义类,并且可以彼此独立使用。

【讨论】:

扩展 SimpleXML 来做到这一点是一个非常好的主意!【参考方案4】:
class Xml 

    public static function from_array($arr, $xml = NULL)
    
        $first = $xml;
        if($xml === NULL) $xml = new SimpleXMLElement('<root/>');
        foreach ($arr as $k => $v) 
        
            is_array($v)
                ? self::from_array($v, $xml->addChild($k))
                : $xml->addChild($k, $v);
        
        return ($first === NULL) ? $xml->asXML() : $xml;
    

    public static function to_array($xml)
    
        $xml = simplexml_load_string($xml);
        $json = json_encode($xml);
        return json_decode($json,TRUE);
    



$xml = xml::from_array($array);
$array = xml::to_array($xml);

【讨论】:

【参考方案5】:

一般尝试 Zend_Config 和 Zend Framework。

我想这将是一个两步过程:数组到 Zend_Config,Zend_Config 到 XML。

【讨论】:

【参考方案6】:

听起来像是 SimpleXML 的工作。

我会建议一个稍微不同的 XML 结构..

想知道为什么需要从数组转换 -> XML 并返回。如果您可以按照您所说的修改数组结构,为什么不直接生成 XML 呢?如果已经存在采用该数组配置的某些代码,只需修改它以接受 XML。然后你有1种数据格式/输入类型,根本不需要转换..

<items>
  <item id="1"/>
  <item id="2"/>
  <item id="3">
  <subitems>     
    <item id="3.1"/>
    <item id="3.2" isawesome="true"/>
  </subitems>
  </item>
</items>

【讨论】:

【参考方案7】:

这是我编写的一个函数,用于获取 XML 并将其转换为 PHP 关联数组。一个警告是 id 当前不处理属性或 c 数据。虽然它会通过将重复的 XML 标签放入以标签命名的数组中来处理同一级别的重复 XML 标签。


<?php

$xml_req1 = <<<XML
<?xml version="1.0"?>
<Vastera:CustomerValidation_RequestInfo
      xmlns:Vastera="http://ndc-ah-prd.am.mot.com:10653/MotVastera_CustomerValidation/MC000078/Docs/">
  <PartnerID>5550000100-003</PartnerID>
  <PartnerType>PTNR_INTER_CONSIGNEE</PartnerType>
  <OperatingUnit>100</OperatingUnit>
  <Status>ACTIVE</Status>
  <CustomerSeqNumber>111</CustomerSeqNumber>
  <CustomerName>Greg Co</CustomerName>
  <Address1>123 Any Ln</Address1>
  <Address2>?</Address2>
  <Address3>?</Address3>
  <Address4>?</Address4>
  <Address5>?</Address5>
  <City>Someplace</City>
  <PostalCode>603021</PostalCode>
  <State>CA</State>
  <CountryCode>US</CountryCode>
  <TaxReference>222</TaxReference>
  <PartyRelated>Y</PartyRelated>
  <BusinessUnit>GSBU</BusinessUnit>
  <Region>GSRGN</Region>
  <LocationName>DBA Mac Head Computing</LocationName>
  <LoadOnly>N</LoadOnly>
  <VSTM>333</VSTM>
  <MilitaryCustomerFlag>Y</MilitaryCustomerFlag>
  <USFederalGovernmentCustomer>Y</USFederalGovernmentCustomer>
  <Non-USGovernmentCustomer>Y</Non-USGovernmentCustomer>
  <Vastera:EPCIActivity>
    <EPCIActivityNuclearCode>NUCLEAR</EPCIActivityNuclearCode>
    <EPCIActivityNuclearValue>N</EPCIActivityNuclearValue>
    <EPCIActivityNuclearApproveDate>2011-05-16:07:19:37</EPCIActivityNuclearApproveDate>
    <EPCIActivityNuclearExpireDate>2056-12-31:12:00:00</EPCIActivityNuclearExpireDate>
    <EPCIActivityNuclearCountry>US</EPCIActivityNuclearCountry>
    <EPCIActivityChemBioCode>CHEM_BIO</EPCIActivityChemBioCode>
    <EPCIActivityChemBioValue>N</EPCIActivityChemBioValue>
    <EPCIActivityChemBioApproveDate>2011-05-16:07:19:37</EPCIActivityChemBioApproveDate>
    <EPCIActivityChemBioExpireDate>2056-12-31:12:00:00</EPCIActivityChemBioExpireDate>
    <EPCIActivityChemBioCountry>US</EPCIActivityChemBioCountry>
    <EPCIActivityMissileCode>MISSILE</EPCIActivityMissileCode>
    <EPCIActivityMissileValue>N</EPCIActivityMissileValue>
    <EPCIActivityMissileApproveDate>2011-05-16:07:19:37</EPCIActivityMissileApproveDate>
    <EPCIActivityMissileExpireDate>2056-12-31:12:00:00</EPCIActivityMissileExpireDate>
    <EPCIActivityMissileCountry>US</EPCIActivityMissileCountry>
  </Vastera:EPCIActivity>
  <SourceSystem>GSB2BSS</SourceSystem>
  <CreatedDate>2011-05-16:07:18:55</CreatedDate>
  <CreatedBy>c18530</CreatedBy>
  <LastModifiedDate>2011-05-16:07:18:55</LastModifiedDate>
  <LastModifiedBy>c18530</LastModifiedBy>
  <ContactName>Greg, "Da Man" Skluacek</ContactName>
  <ContactTitle>Head Honcho</ContactTitle>
  <ContactPhone>555-555-5555</ContactPhone>
  <ContactFax>666-666-6666</ContactFax>
  <ContactEmail>gskluzacek@gregco.com</ContactEmail>
  <ContactWeb>www.gregco.com</ContactWeb>
</Vastera:CustomerValidation_RequestInfo>
XML;

$xml_req2 = <<<XML
<?xml version="1.0"?>
<order>
    <orderNumber>123</orderNumber>
    <customerAddress>
        <type>Ship To</type>
        <name>Bob McFly</name>
        <addr1>123 Lincoln St</addr1>
        <city>Chicago</city>
        <state>IL</state>
        <zip>60001</zip>
    </customerAddress>
    <customerAddress>
        <type>Bill To</type>
        <name>McFly Products Inc.</name>
        <addr1>P.O. Box 6695</addr1>
        <city>New York</city>
        <state>NY</state>
        <zip>99081-6695</zip>
    </customerAddress>
    <item>
        <line>1</line>
        <part>123001A</part>
        <qty>5</qty>
        <price>10.25</price>
    </item>
    <item>
        <line>2</line>
        <part>456002B</part>
        <qty>3</qty>
        <price>20.50</price>
    </item>
    <item>
        <line>3</line>
        <part>789003C</part>
        <qty>1</qty>
        <price>41.00</price>
    </item>
    <orderSubTotal>133.25</orderSubTotal>
    <tax>6.66</tax>
    <shipping>10.00</shipping>
    <orderTotal>149.91</orderTotal>
</order>
XML;

$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->loadXML($xml_req1);

$arr = xml_to_arr($doc->documentElement);

print "\n\n----\n\n";

print_r($arr);

print "\n\n----\n\n";

$doc2 = new DOMDocument();
$doc2->preserveWhiteSpace = false;
$doc2->loadXML($xml_req2);

$arr2 = xml_to_arr($doc2->documentElement);

print "\n\n----\n\n";

print_r($arr2);

print "\n\n----\n\n";

exit;

function xml_to_arr($curr_node) 
    $val_array = array();
    $typ_array = array();

    foreach($curr_node->childNodes as $node) 
        if ($node->nodeType == XML_ELEMENT_NODE) 

            $val = xml_to_arr($node);

            if (array_key_exists($node->tagName, $val_array)) 

                if (!is_array($val_array[$node->tagName]) || $type_array[$node->tagName] == 'hash') 
                    $existing_val = $val_array[$node->tagName];
                    unset($val_array[$node->tagName]);
                    $val_array[$node->tagName][0] = $existing_val;
                    $type_array[$node->tagName] = 'array';
                
                $val_array[$node->tagName][] = $val;

             else 

                $val_array[$node->tagName] = $val;
                if (is_array($val)) 
                    $type_array[$node->tagName] = 'hash';
                

             // end if array key exists

         // end if elment node
    // end for each

    if (count($val_array) == 0) 
        return $curr_node->nodeValue;
     else 
        return $val_array;
    

 // end function xml to arr

?>

示例输出


----

Array
(
    [PartnerID] => 5550000100-003
    [PartnerType] => PTNR_INTER_CONSIGNEE
    [OperatingUnit] => 100
    [Status] => ACTIVE
    [CustomerSeqNumber] => 111
    [CustomerName] => Greg Co
    [Address1] => 123 Any Ln
    [Address2] => ?
    [Address3] => ?
    [Address4] => ?
    [Address5] => ?
    [City] => Somplace
    [PostalCode] => 60123
    [State] => CA
    [CountryCode] => US
    [TaxReference] => 222
    [PartyRelated] => Y
    [BusinessUnit] => GSBU
    [Region] => GSRGN
    [LocationName] => DBA Mac Head Computing
    [LoadOnly] => N
    [VSTM] => 333
    [MilitaryCustomerFlag] => Y
    [USFederalGovernmentCustomer] => Y
    [Non-USGovernmentCustomer] => Y
    [Vastera:EPCIActivity] => Array
        (
            [EPCIActivityNuclearCode] => NUCLEAR
            [EPCIActivityNuclearValue] => N
            [EPCIActivityNuclearApproveDate] => 2011-05-16:07:19:37
            [EPCIActivityNuclearExpireDate] => 2056-12-31:12:00:00
            [EPCIActivityNuclearCountry] => US
            [EPCIActivityChemBioCode] => CHEM_BIO
            [EPCIActivityChemBioValue] => N
            [EPCIActivityChemBioApproveDate] => 2011-05-16:07:19:37
            [EPCIActivityChemBioExpireDate] => 2056-12-31:12:00:00
            [EPCIActivityChemBioCountry] => US
            [EPCIActivityMissileCode] => MISSILE
            [EPCIActivityMissileValue] => N
            [EPCIActivityMissileApproveDate] => 2011-05-16:07:19:37
            [EPCIActivityMissileExpireDate] => 2056-12-31:12:00:00
            [EPCIActivityMissileCountry] => US
        )

    [SourceSystem] => GSB2BSS
    [CreatedDate] => 2011-05-16:07:18:55
    [CreatedBy] => c18530
    [LastModifiedDate] => 2011-05-16:07:18:55
    [LastModifiedBy] => c18530
    [ContactName] => Greg, "Da Man" Skluacek
    [ContactTitle] => Head Honcho
    [ContactPhone] => 555-555-5555
    [ContactFax] => 666-666-6666
    [ContactEmail] => gskluzacek@gregco.com
    [ContactWeb] => www.gregco.com
)

----

Array
(
    [orderNumber] => 123
    [customerAddress] => Array
        (
            [0] => Array
                (
                    [type] => Ship To
                    [name] => Bob McFly
                    [addr1] => 123 Lincoln St
                    [city] => Chicago
                    [state] => IL
                    [zip] => 60001
                )

            [1] => Array
                (
                    [type] => Bill To
                    [name] => McFly Products Inc.
                    [addr1] => P.O. Box 6695
                    [city] => New York
                    [state] => NY
                    [zip] => 99081-6695
                )

        )

    [item] => Array
        (
            [0] => Array
                (
                    [line] => 1
                    [part] => 123001A
                    [qty] => 5
                    [price] => 10.25
                )

            [1] => Array
                (
                    [line] => 2
                    [part] => 456002B
                    [qty] => 3
                    [price] => 20.50
                )

            [2] => Array
                (
                    [line] => 3
                    [part] => 789003C
                    [qty] => 1
                    [price] => 41.00
                )

        )

    [orderSubTotal] => 133.25
    [tax] => 6.66
    [shipping] => 10.00
    [orderTotal] => 149.91
)

--------

【讨论】:

【参考方案8】:

嘿@Co​​nrad,我只是修改了您的代码,以便与数字数组一起工作:

/**
 * Build A 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
 */
public static 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 XML as per Associative Array
     * @param object $xml XMLWriter Object
     * @param array $data Associative Data Array
     */
    function write(XMLWriter $xml, $data)
        foreach($data as $key => $value)
            if (is_array($value) && isset($value[0]))
                foreach($value as $itemValue)
                    //$xml->writeElement($key, $itemValue);

                    if(is_array($itemValue))
                        $xml->startElement($key);
                        write($xml, $itemValue);
                        $xml->endElement();
                        continue;
                     

                    if (!is_array($itemValue))
                        $xml->writeElement($key, $itemValue."");
                    
                
            else if(is_array($value))
                $xml->startElement($key);
                write($xml, $value);
                $xml->endElement();
                continue;
             

            if (!is_array($value))
                $xml->writeElement($key, $value."");
            
        
    
    write($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;

进入这个xml:

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

我希望我能帮助别人解决这个问题

【讨论】:

【参考方案9】:

你见过 PEAR 包 XML_Serializer 吗?

pear_php_XML_Serializer

【讨论】:

【参考方案10】:

我同意这是 PHP 文档已经放弃的一个领域,但对我来说,我总是将 SimpleXML 与 xml2Array 函数之类的东西混合使用。借助 print_r 之类的转储函数,您从 simpleXML 获得的 Xml 并不难导航。

【讨论】:

【参考方案11】:

这建立在 Á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;

进入这个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>

谢谢天使。

【讨论】:

很酷,但如果你像这样制作 assoc 数组,它就不起作用了:array('123' =&gt; 'asdf') 也许你应该检查每个键是否是数字。【参考方案12】:

根据这里的答案,我制作了 github repo https://github.com/jmarceli/array2xml

也许不是互联网上最漂亮的 repo,但代码似乎运行良好。

这里是可以使用的代码:

// Based on: http://***.com/questions/99350/passing-php-associative-arrays-to-and-from-xml
class ArrayToXML 
  private $version;
  private $encoding;
  /*
   * Construct ArrayToXML object with selected version and encoding 
   *
   * for available values check XmlWriter docs http://www.php.net/manual/en/function.xmlwriter-start-document.php
   * @param string $xml_version XML Version, default 1.0
   * @param string $xml_encoding XML Encoding, default UTF-8
   */
  public function __construct($xmlVersion = '1.0', $xmlEncoding = 'UTF-8') 
    $this->version = $xmlVersion;
    $this->encoding = $xmlEncoding;
  
  /**
   * 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 data
   * @return string XML String containig values
   * @return mixed Boolean false on failure, string XML result on success
   */
  public function buildXML($data, $startElement = 'data')
    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($this->version, $this->encoding);
    $xml->startElement($startElement);
    $this->writeEl($xml, $data);
    $xml->endElement();//write end element
    //returns the XML results
    return $xml->outputMemory(true);
  
  /**
   * 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, 
   * and '#' prefixed key indicates CDATA content
   *
   * @param object $xml XMLWriter Object
   * @param array $data with attributes filtered out
   */
  protected 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[0] == '%') 
          if(is_array($val)) $nonAttributes = $val;
          else $xml->text($val);
         elseif($key[0] == '#') 
          if(is_array($val)) $nonAttributes = $val;
          else 
            $xml->startElement(substr($key, 1));
            $xml->writeCData($val);
            $xml->endElement();
          
        
        //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
   */
  protected function writeEl(XMLWriter $xml, $data) 
    foreach($data as $key => $value) 
      if(is_array($value) && !$this->isAssoc($value))  //numeric array
        foreach($value as $itemValue)
          if(is_array($itemValue)) 
            $xml->startElement($key);
            $itemValue = $this->writeAttr($xml, $itemValue);
            $this->writeEl($xml, $itemValue);
            $xml->endElement();
           else 
            $itemValue = $this->writeAttr($xml, $itemValue);
            $xml->writeElement($key, "$itemValue");
          
        
       else if(is_array($value))  //associative array
        $xml->startElement($key);
        $value = $this->writeAttr($xml, $value);
        $this->writeEl($xml, $value);
        $xml->endElement();
       else  //scalar
        $value = $this->writeAttr($xml, $value);
        $xml->writeElement($key, "$value");
      
    
  
  /*
   * Check if array is associative with string based keys
   * FROM: http://***.com/questions/173400/php-arrays-a-good-way-to-check-if-an-array-is-associative-or-sequential/4254008#4254008
   *
   * @param array $array Array to check
   */
  protected function isAssoc($array) 
    return (bool)count(array_filter(array_keys($array), 'is_string'));
  

之后,只需使用 ArrayToXML 类。示例:

$xml = new ArrayToXML();
print $xml->buildXML($input);

【讨论】:

【参考方案13】:

下面的类使用simplexml实现相同,只需要遍历数组并调用ximplexml的addchild即可。

http://snipplr.com/view.php?codeview&id=3491

【讨论】:

【参考方案14】:

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

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

【讨论】:

【参考方案15】:
/**
 * 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."");
        
    

这是最终版本,它可以从具有 4 个嵌套级别的数组中提供我想要的 ahat

<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>

【讨论】:

以上是关于将 PHP 关联数组传入和传出 XML的主要内容,如果未能解决你的问题,请参考以下文章

如何循环访问和访问多维和关联数组中的各种元素? PHP,JSON 或 XML

php 数组索引值如何重新从0开始递增

php判断数组是关联数组还是数值数组

将xml文本数组转换为关联数组[重复]

PHP - 将两个数组(相同长度)合并为一个关联?

php Laravel Collection将数组转换为关联数组