我正在寻找基于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是否有办法满足开箱即用的需求,或者是否需要额外的框架。
答案 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>