- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我对 PHP、DOM 和 PHP DOM 实现还很陌生。我想要做的是将 DOMDocument
的根元素保存在 $_SESSION
变量中,以便我可以访问它并在后续页面加载时修改它。
但是当使用 $_SESSION
保存 DOMElement 的状态时,我在 PHP 中遇到错误:
Warning: DOMNode::appendChild() [domnode.appendchild]: Couldn't fetch DOMElement
我读到 PHP DOMDocument 对象无法保存到 $_SESSION
中。然而,它可以通过保存 DOMDocument 的序列化来保存(例如 $_SESSION['dom'] = $dom->saveXML()
)。
我不知道将 DOMElement
保存到 $_SESSION
变量是否也是如此,但这就是我正在尝试的。我想要这样做的原因是使用具有一个附加属性的扩展类 DOMElement。我希望通过将根 DOMElement 保存在 $_SESSION 中,我以后可以检索该元素并修改此附加属性并执行测试,如 if (additionalProperty === false) { do something; }.我还读到,通过保存 DOMDocument 并在稍后检索它,所有元素都作为对象从 native DOM 类返回。也就是说,即使我使用扩展类创建元素,我随后需要的属性也将无法访问,因为持有扩展类对象引用的变量已经超出范围——这就是为什么我我正在尝试另一件事。我首先尝试使用扩展类(下面未包含),但出现错误...所以我恢复使用 DOMElement 对象来查看是否是问题所在,但我仍然遇到相同的错误。这是代码:
<?php
session_start();
$rootTag = 'root';
$doc = new DOMDocument;
if (!isset($_SESSION[$rootTag])) {
$_SESSION[$rootTag] = new DOMElement($rootTag);
}
$root = $doc->appendChild($_SESSION[$rootTag]);
//$root = $doc->appendChild($doc->importNode($_SESSION[$rootTag], true));
$child = new DOMElement('child_element');
$n = $root->appendChild($child);
$ct = 0;
foreach ($root->childNodes as $ch) echo '<br/>'.$ch->tagName.' '.++$ct;
$_SESSION[$rootTag] = $doc->documentElement;
?>
这段代码给出了以下错误(取决于我是直接使用 appendChild 还是使用 importNode 的注释代码行):
警告:DOMNode::appendChild() [domnode.appendchild]:无法在第 11 行获取 C:\Program Files\wamp_server_2.2\www\test2.php 中的 DOMElement
/p>
警告:DOMDocument::importNode() [domdocument.importnode]:无法在第 12 行的 C:\Program Files\wamp_server_2.2\www\test2.php 中获取 DOMElement
我有几个问题。首先,是什么导致了这个错误,我该如何解决?此外,如果我尝试做的事情是不可能的,那么我如何才能在为每个元素使用自定义属性的同时实现保存 DOM 树“状态”的总体目标?请注意,附加属性仅在程序中使用,而不是要保存在 XML 文件中的属性。此外,我不能每次都将 DOM 保存回文件,因为修改后的 DOMDocument 可能根据我正在使用的模式无效,直到稍后对 DOMDocument 执行了额外的修改/添加。这就是为什么我需要保存一个暂时无效的 DOMDocument。感谢您的任何建议!
编辑:在尝试了 hakre 的解决方案之后,代码成功了。然后我继续尝试使用 DOMElement 的扩展类,但正如我所怀疑的那样,它不起作用。这是新代码:
<?php
session_start();
//$_SESSION = array();
$rootTag = 'root';
$doc = new DOMDocument;
if (!isset($_SESSION[$rootTag])) {
$root = new FreezableDOMElement($rootTag);
$doc->appendChild($root);
} else {
$doc->loadXML($_SESSION[$rootTag]);
$root = $doc->documentElement;
}
$child = new FreezableDOMElement('child_element');
$n = $root->appendChild($child);
$ct = 0;
foreach ($root->childNodes as $ch) {
$frozen = $ch->frozen ? 'is frozen' : 'is not frozen';
echo '<br/>'.$ch->tagName.' '.++$ct.': '.$frozen;
//echo '<br/>'.$ch->tagName.' '.++$ct;
}
$_SESSION[$rootTag] = $doc->saveXML();
/**********************************************************************************
* FreezableDOMElement class
*********************************************************************************/
class FreezableDOMElement extends DOMElement {
public $frozen; // boolean value
public function __construct($name) {
parent::__construct($name);
$this->frozen = false;
}
}
?>
它给我错误 Undefined property: DOMElement::$frozen
。正如我在原来的帖子中提到的,在 saveXML
和 loadXML
之后,最初使用 FreezableDOMElement
实例化的元素返回类型 DOMElement
这就是无法识别 frozen
属性的原因。有什么办法解决这个问题吗?
最佳答案
您不能在 $_SESSION
中存储 DOMElement
对象。一开始它会工作,但在下一个请求中,它将被取消设置,因为它无法序列化。
这与您在问题中所写的 DOMDocument
相同。
改为将其存储为 XML 或封装序列化机制。
你在这里基本上面临三个问题:
DOMDocument
(您这样做是为了)FreezableDOMElement
(您这样做是为了)FreezableDOMElement::$frozen
与文档保持在一起。正如所写,序列化不是开箱即用的。此外,即使没有序列化,DOMDocument
也不会保留您的 FreezableDOMElement
。以下示例演示了实例不会自动保留,返回默认值 FALSE
( Demo ):
class FreezableDOMElement extends DOMElement
{
private $frozen = FALSE;
public function getFrozen()
{
return $this->frozen;
}
public function setFrozen($frozen)
{
$this->frozen = (bool)$frozen;
}
}
class FreezableDOMDocument extends DOMDocument
{
public function __construct()
{
parent::__construct();
$this->registerNodeClass('DOMElement', 'FreezableDOMElement');
}
}
$doc = new FreezableDOMDocument();
$doc->loadXML('<root><child></child></root>');
# own objects do not persist
$doc->documentElement->setFrozen(TRUE);
printf("Element is frozen (should): %d\n", $doc->documentElement->getFrozen()); # it is not (0)
由于 PHP 目前还不支持 setUserData
(DOM 级别 3),一种方法是将附加信息存储在带有元素的命名空间属性中。这也可以通过在序列化对象时创建 XML 字符串并在反序列化时加载它来序列化(参见 Serializable
)。这样就解决了所有三个问题 ( Demo ):
class FreezableDOMElement extends DOMElement
{
public function getFrozen()
{
return $this->getFrozenAttribute()->nodeValue === 'YES';
}
public function setFrozen($frozen)
{
$this->getFrozenAttribute()->nodeValue = $frozen ? 'YES' : 'NO';
}
private function getFrozenAttribute()
{
return $this->getSerializedAttribute('frozen');
}
protected function getSerializedAttribute($localName)
{
$namespaceURI = FreezableDOMDocument::NS_URI;
$prefix = FreezableDOMDocument::NS_PREFIX;
if ($this->hasAttributeNS($namespaceURI, $localName)) {
$attrib = $this->getAttributeNodeNS($namespaceURI, $localName);
} else {
$this->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:' . $prefix, $namespaceURI);
$attrib = $this->ownerDocument->createAttributeNS($namespaceURI, $prefix . ':' . $localName);
$attrib = $this->appendChild($attrib);
}
return $attrib;
}
}
class FreezableDOMDocument extends DOMDocument implements Serializable
{
const NS_URI = '/frozen.org/freeze/2';
const NS_PREFIX = 'freeze';
public function __construct()
{
parent::__construct();
$this->registerNodeClasses();
}
private function registerNodeClasses()
{
$this->registerNodeClass('DOMElement', 'FreezableDOMElement');
}
/**
* @return DOMNodeList
*/
private function getNodes()
{
$xp = new DOMXPath($this);
return $xp->query('//*');
}
public function serialize()
{
return parent::saveXML();
}
public function unserialize($serialized)
{
parent::__construct();
$this->registerNodeClasses();
$this->loadXML($serialized);
}
public function saveBareXML()
{
$doc = new DOMDocument();
$doc->loadXML(parent::saveXML());
$xp = new DOMXPath($doc);
foreach ($xp->query('//@*[namespace-uri()=\'' . self::NS_URI . '\']') as $attr) {
/* @var $attr DOMAttr */
$attr->parentNode->removeAttributeNode($attr);
}
$doc->documentElement->removeAttributeNS(self::NS_URI, self::NS_PREFIX);
return $doc->saveXML();
}
public function saveXMLDirect()
{
return parent::saveXML();
}
}
$doc = new FreezableDOMDocument();
$doc->loadXML('<root><child></child></root>');
$doc->documentElement->setFrozen(TRUE);
$child = $doc->getElementsByTagName('child')->item(0);
$child->setFrozen(TRUE);
echo "Plain XML:\n", $doc->saveXML(), "\n";
echo "Bare XML:\n", $doc->saveBareXML(), "\n";
$serialized = serialize($doc);
echo "Serialized:\n", $serialized, "\n";
$newDoc = unserialize($serialized);
printf("Document Element is frozen (should be): %s\n", $newDoc->documentElement->getFrozen() ? 'YES' : 'NO');
printf("Child Element is frozen (should be): %s\n", $newDoc->getElementsByTagName('child')->item(0)->getFrozen() ? 'YES' : 'NO');
它不是真正的功能完整,而是一个工作演示。无需额外的“卡住”数据即可获得完整的 XML。
关于php - 如何在 $_SESSION 中序列化/保存 DOMElement?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10398147/
我正在阅读 Python 文档以真正深入了解 Python 语言,并遇到了 filter 和 map 函数。我以前使用过过滤器,但从未使用过映射,尽管我在 SO 上的各种 Python 问题中都见过这
当我尝试打印 BST 的级别顺序时,这个问题提示了我。 这是一个 Pre-Order Sequence: 4, 1, 2, 3, 5, 6, 7, 8 In_order Sequence : 1, 2
我的代码在 main(序列测试;)的第一行出现错误,指出它是对 sequence::sequence() 的 undefined reference 。我无法更改 main 中的代码。有谁知道我该如何
这可能很简单,但我在通常的 latex 指南中找不到任何相关内容。在这句话中: {\em hello\/} “\/”的目的是什么? 最佳答案 这就是所谓的斜体校正。其目的是确保斜体文本后有适当的间距。
当我从 Postgresql 表中删除所有记录,然后尝试重置序列以在插入时开始一个编号为 1 的新记录时,我得到不同的结果: SELECT setval('tblname_id_seq', (SELE
在版本10.0.3中,MariaDB引入了一种称为序列的存储引擎。 其ad hoc为操作生成整数序列,然后终止。 该序列包含正整数,以降序或升序排列,并使用起始,结束和递增值。 它不允许在多个查询中
如何在 Groovy 中获取给定数字的序列,例如: def number = 169 // need a method in groovy to find the consecutive number
基本上,如果这是 .NET,它看起来像这样: ISomething { string A { get; } int B { get; } } var somethings = new List
说以下代码部分(同一块): A <= 1 A <= 2 变量 A 总是被赋值为 2 吗?还是会出现竞争条件并分配 1 或 2? 我对非阻塞赋值的理解是,由硬件在 future 分配变量 A,因此它可能
在运行 WiX 设置时,我正在寻找操作列表及其顺序。不知何故,官方网站似乎没有提供任何信息。 基本问题是我想正确安排我的自定义操作。通常我需要使用 regsvr32.exe 注册一个 DLL,而这只能
F#初学者在这里 我想创建一个类型,它是具有至少一个元素的另一种具体类型(事件)的序列。任何其他元素都可以在以后随时添加。通常在 C# 中,我会创建一个具有私有(private) List 和公共(p
作为构建过程和不断发展的数据库的一部分,我试图创建一个脚本,该脚本将删除用户的所有表和序列。我不想重新创建用户,因为这将需要比所允许的更多的权限。 我的脚本创建了一个过程来删除表/序列,执行该过程,然
我想恢复两个向量的第一个日期和相同向量的第二个日期之间的日期序列,.... 这是一个例子: dates1 = as.Date(c('2015-10-01', '2015-03-27', '2015-0
这个问题已经有答案了: sql ORDER BY multiple values in specific order? (12 个回答) 已关闭 9 年前。 我有一个 sql 语句,我想要ORDER
我想恢复两个向量的第一个日期和相同向量的第二个日期之间的日期序列,.... 这是一个例子: dates1 = as.Date(c('2015-10-01', '2015-03-27', '2015-0
在用java编写代码时,我需要用“],[”分割字符串。下面是我的代码。 try (BufferedReader reader = new BufferedReader(new InputStreamR
这个问题已经有答案了: Project Euler Question 14 (Collatz Problem) (8 个回答) 已关闭 9 年前。 我正在尝试查找数字的 Collatz 序列。以下
我有一个例程函数process_letter_location(const char& c, string &word)。 在我的 main 中,我声明了一系列字符串变量,如下所示: string s
我需要找到最长的多米诺骨牌链,给定一组 12 个随机挑选的多米诺骨牌。我已经递归地生成了多米诺骨牌的所有可能性(使用 0 到 12 的面值有 91 种可能性)。多米诺骨牌由一 block “砖 blo
我有这个数据结构 Seq,它继承了类 vector 但有一些额外的功能。使用这个数据结构 Seq 我有这个预定义的数据结构: typedef Seq > MxInt2d; 我现在想要一个包含多个 Mx
我是一名优秀的程序员,十分优秀!