首页 > 解决方案 > 如何使用命名空间创建数组到 SOAPXML?

问题描述

我需要以下格式的输出:

 <ns1:CustomerDetails>
      <_cd:Name>My Name</_cd:Name>
            <_pd:PersonalDetails>
               <_bio:Age>20</_bio:Age>
            </_pd:PersonalDetails>
     <_cd:SomeVar>Var Value</_cd:SomeVar>
</ns1:CustomerDetails>

我可以创建任何格式的数组,例如:

$vars['ns1']['CustomerDetails']['_cd']['Name']="MY Name";
$vars['ns1']['CustomerDetails']['_pd']['PersonalDetails']['_bio']['Age']="20";
$vars['ns1']['CustomerDetails']['_cd']['SomeVars']="Var Value";

我使用了以下代码:

class ArrToXml{

    static function parse($arr){
        $dom = new DOMDocument('1.0');
 
        self::recursiveParser($dom,$arr,$dom);
        return $dom->saveXML();
    }

    private static function recursiveParser(&$root, $arr, &$dom){
         foreach($arr as $key => $item){
            if(is_array($item) && !is_numeric($key)){
                $node = $dom->createElement($key);
                self::recursiveParser($node,$item,$dom);
                $root->appendChild($node);
            }elseif(is_array($item) && is_numeric($key)){
                self::recursiveParser($root,$item,$dom);
            }else{
                $node = $dom->createElement($key, $item);
                $root->appendChild($node);
            }
        }
    }

           }

    $xmlRequest = ArrToXml::parse($requestArray);

...但我没有得到命名空间值。我应该在代码中做哪些更改以获得我想要的值?

标签: phpxml

解决方案


数据数组不允许区分命名空间指示符和标签名称。两者都只是钥匙。一种解决方案是使用 QCNames 作为键:

$data = [
    'c:CustomerDetails' => [
        'cd:Name' => "MY Name",
        'pd:PersonalDetails' => [
            'bio:Age' => "20" 
        ],
        'cd:SomeVars' => "Var Value",
    ]     
]; 

此外,您还需要指标的命名空间信息:

$xmlns = [
    'c' => ['prefix' => 'ns1', 'uri' => 'urn:c'],
    'cd' => ['prefix' => '_cd', 'uri' => 'urn:cd'],
    'pd' => ['prefix' => '_pd', 'uri' => 'urn:pd'],
    'bio' => ['prefix' => '_bio', 'uri' => 'urn:bio']
];

我建议包括一个前缀来解耦代码。

大多数情况下,将数据直接附加到 DOM 是一种更好、更简单的解决方案。我通常为此定义一个接口并在不同的数据和序列化程序类中实现它:

interface XMLAppendable {
    public function appendTo(DOMNode $parentNode);
}

数据数组的映射器也可以实现接口。它需要数据数组和有关命名空间的信息。

class ArrayAppender implements XMLAppendable {
    
    private $_data;
    private $_xmlns;
    
    public function __construct(array $data, array $xmlns = []) {
        $this->_data = $data;
        $this->_xmlns = $xmlns;
    }
    
    public function appendTo(DOMNode $parentNode) {
        $this->appendArrayTo($parentNode, $this->_data);
    }
        
    private function appendArrayTo(DOMNode $parentNode, array $data) {    
        $document = $parentNode instanceof DOMDocument 
            ? $parentNode : $parentNode->ownerDocument;
        foreach ($data as $key => $value) {
            if (FALSE !== strpos($key, ':')) {
                [$prefix, $tagName] = explode(':', $key);
                if (isset($this->_xmlns[$prefix])) {
                    $namespace = $this->_xmlns[$prefix];
                } else {
                    throw new UnexpectedValueException(
                        'Can not find namespace for '.$prefix
                    );
                }
            } else {
                $namespace = ['prefix' => '', 'uri' => ''];
                $tagName = $key;
            } 
            $parentNode->appendChild(
                $child = $document->createElementNS(
                    $namespace['uri'], 
                    $namespace['prefix'] ? $namespace['prefix'].':'.$tagName : $tagName
                )
            );
            if (is_array($value)) {
                $this->appendArrayTo($child, $value);
            } else {
                $child->textContent = (string)$value;
            }
        }
    }
}

使用演示:

$document = new DOMDocument();
$arrayToXML = new ArrayAppender($data, $xmlns);
$arrayToXML->appendTo($document);
$document->formatOutput = TRUE;
echo $document->saveXML();

输出:

<?xml version="1.0"?>
<ns1:CustomerDetails xmlns:ns1="urn:c">
  <_cd:Name xmlns:_cd="urn:cd">MY Name</_cd:Name>
  <_pd:PersonalDetails xmlns:_pd="urn:pd">
    <_bio:Age xmlns:_bio="urn:bio">20</_bio:Age>
  </_pd:PersonalDetails>
  <_cd:SomeVars xmlns:_cd="urn:cd">Var Value</_cd:SomeVars>
</ns1:CustomerDetails>

推荐阅读