基于php

时间:2017-12-03 21:37:24

标签: php xml simplexml

我正在寻找基于PHP模式创建XML文档的方法。

默认的PHP go-to解决方案通常是SimpleXMLElement,但顾名思义,它适用于创建简单的XML文档,但如果您需要创建更复杂的文档,则会成为负担。

考虑以下架构,例如:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="test">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="step1" type="xs:string" minOccurs="0"/>
                <xs:element name="step2" type="xs:string" minOccurs="0"/>
                <xs:element name="step3" type="xs:string" minOccurs="0"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

这需要元素&#34; step1&#34;,&#34; step2&#34;和&#34; step3&#34;如果存在于文件中,则按一定顺序排列。

为了使用SimpleXMLElement创建符合上述模式的文档,您需要知道以哪种顺序&#34; step1&#34;和&#34; step2&#34;需要在文件中。例如,以下将无法创建有效的文档:

$xml=new SimpleXMLElement('<test/>');
$xml->step2='This is step 2';
$xml->step1='This is step 1';
print $xml->asXML();

输出有&#34; step1&#34;和&#34; step2&#34;错误的顺序。

PHP是否具有内置功能来构建符合特定模式的XML文档?例如,在上面的代码中,所需的功能是根据模式的要求正确排序元素,而不是基于它们的添加顺序。

快速浏览一下,DOMDocument和XMLWriter在生成文档时都不支持使用模式,即使DOMDocument可以对其进行验证。

<小时/> 编辑以进一步强调用例:

考虑以下极其简化的XML,例如:

<test>
    <sender>
        <name>Sender 1</name>
        <addr>192.168.0.1</addr>
        <descr>This is the peer sending the information</descr>
    </sender>
    <receiver>
        <name>Gateway 1</name>
        <addr>10.2.1.2</addr>
        <descr>This is the intended recipient</descr>
    </receiver>
</test>

在问题的上下文中,我希望从数据中删除代码,以便将//sender//recipient添加到数据中的顺序并不重要。文档。

目的是最小化将PHP对象(或其他结构)序列化为XML文档所需的样板代码。

目前有一种可能性是首先将信息存储到对象中,然后将其序列化为XML文档:

class XMLDoc1 {
    private $sender=[];
    private $receiver=[];

    public function setParty($name, $addr, $descr) {
        $res['name']=$name;
        $res['addr']=$addr;
        $res['descr']=$descr;
        return $res;
    }

    public function setSender($name, $addr, $descr) {
        $this->sender=$this->setParty($name,$addr,$descr);
    }

    public function setReceiver($name, $addr, $descr) {
        $this->receiver=$this->setParty($name,$addr,$descr);
    }

    public function setXmlParty(SimpleXMLElement $node, $party) {
        $node->name=$party['name'];
        $node->addr=$party['addr'];
        $node->descr=$party['descr'];
    }

    public function getxml() {
        $xml=new SimpleXMLElement('<test/>');
        $this->setXmlParty($xml->addChild('sender'),$this->sender);
        $this->setXmlParty($xml->addChild('receiver'),$this->receiver);
        return $xml->asXML();
    }
}

$x=new XMLDoc1();
$x->setSender('Origin', '192.168.0.2','Party sending the information');
$x->setReceiver('Target','10.2.1.3','Intended recipient of the information');
print $x->getxml();

上面的代码将保证始终以正确的顺序生成XML元素。

也就是说,首选是能够将数据直接存储到XML文档本身并在运行中进行修改,同时始终保持有效。有点像:

class XMLDoc2 {
    /** @var SimpleXMLElement */
    private $xml;

    public function __construct() {
        $this->xml=new SimpleXMLElement('<test/>');
    }

    public function setParty(SimpleXMLElement $node, $name, $addr, $descr) {
        $node->name=$name;
        $node->addr=$addr;
        $node->descr=$descr;
    }

    public function setSender($name, $addr, $descr) {
        $this->setParty($this->xml->addChild('sender'),$name,$addr,$descr);
    }

    public function setReceiver($name, $addr, $descr) {
        $this->setParty($this->xml->addChild('receiver'),$name,$addr,$descr);
    }

    public function getxml() {
        return $this->xml->asXML();
    }

}

$x=new XMLDoc2();
$x->setReceiver('Target','10.2.1.3','Intended recipient of the information');
$x->setSender('Origin', '192.168.0.2','Party sending the information');
print $x->getxml();

如果以正确的顺序调用setReceiver()setSender(),则此代码有效。

将信息序列化到XML所需的更复杂的文档样板代码变得相当可观,并且基本上复制了XSD中已定义的内容。

问题的核心是PHP是否有办法满足开箱即用的需求,或者是否需要额外的框架。

1 个答案:

答案 0 :(得分:0)

以下DTO类提供了数据传输方法,并将此数据呈现为所需的有效输出格式(在本例中为XML)。

代码:

class XMLDoc2
{
    private $senders = [];

    private $receivers = [];

    public function addSender($name, $addr, $descr)
    {
        $this->senders[] = ['name' => $name, 'addr' => $addr, 'descr' => $descr];
    }

    public function addReceiver($name, $addr, $descr)
    {
        $this->receivers[] = ['name' => $name, 'addr' => $addr, 'descr' => $descr];
    }

    public function getXml()
    {
        $xml = new DOMDocument("1.0", "UTF-8");
        $xml->preserveWhiteSpace = false;
        $xml->formatOutput = true;

        $root = $xml->createElement("test");

        foreach ($this->senders as $sender) {
            $senderNode = $this->createParty($xml, 'sender', $sender['name'], $sender['addr'], $sender['descr']);
            $root->appendChild($senderNode);
        }

        foreach ($this->receivers as $receiver) {
            $receiverNode = $this->createParty($xml, 'receiver', $receiver['name'], $receiver['addr'], $receiver['descr']);
            $root->appendChild($receiverNode);
        }

        $xml->appendChild($root);

        return $xml->saveXML();
    }

    private function createParty(DOMDocument $xml, $elementName, $name, $addr, $descr)
    {
        $node = $xml->createElement($elementName);

        $node->appendChild($xml->createElement("name", $name));
        $node->appendChild($xml->createElement("addr", $addr));
        $node->appendChild($xml->createElement("descr", $descr));

        return $node;
    }

}

$x = new XMLDoc2();
$x->addReceiver('Target', '10.2.1.3', 'Intended recipient of the information');
$x->addSender('Origin', '192.168.0.2', 'Party sending the information');
echo $x->getXml();

输出:

<?xml version="1.0" encoding="UTF-8"?>
<test>
  <sender>
    <name>Origin</name>
    <addr>192.168.0.2</addr>
    <descr>Party sending the information</descr>
  </sender>
  <receiver>
    <name>Target</name>
    <addr>10.2.1.3</addr>
    <descr>Intended recipient of the information</descr>
  </receiver>
</test>