0

XPath クエリを簡単にするために、2 つのネイティブ PHP5 クラス (DOMDocument と DOMNode) を拡張して 2 つのメソッド (selectNodes と selectSingleNode) を実装しようとしています。かなり簡単だと思いましたが、OOPの初心者の問題だと思う問題に行き詰まっています。

class nDOMDocument extends DOMDocument {
    public function selectNodes($xpath){
    $oxpath = new DOMXPath($this);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}

次に、DOMNode を拡張して同じメソッドを実装しようとしたので、ノードで直接 XPath クエリを実行できます。

class nDOMNode extends DOMNode {
    public function selectNodes($xpath){
    $oxpath = new DOMXPath($this->ownerDocument,$this);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}

次に、(任意の XMLDocument で) 次のコードを実行すると:

$xmlDoc = new nDOMDocument;
$xmlDoc->loadXML(...some XML...);
$node1 = $xmlDoc->selectSingleNode("//item[@id=2]");
$node2 = $node1->selectSingleNode("firstname");

3 行目は機能し、DOMNode オブジェクト $node1 を返します。ただし、selectSingleNode メソッドは DOMNode ではなく nDOMNode クラスに属しているため、4 行目は機能しません。私の質問: 返された DOMNode オブジェクトを nDOMNode オブジェクトに「変換」する方法はありますか? ここでいくつかの重要な点が欠けているように感じます。助けていただければ幸いです。

(申し訳ありませんが、これは私の質問の言い直しです DOMDocument と DOMNode の拡張: return オブジェクトの問題)

4

5 に答える 5

2

特定のノードタイプのオブジェクトをインスタンス化するときに、デフォルトのクラスの代わりに使用するクラスをDOMDocument :: registerNodeClass()を介してDOMDocumentに「通知」できます。例えば

$doc->registerNodeClass('DOMElement', 'Foo');

domが「通常」インスタンス化するたびにDOMElement、のインスタンスが作成されますFoo

$doc = new nDOMDocument;
$doc->loadxml('<a><b><c>foo</c></b></a>');

$a = $doc->selectSingleNode('//a');
$c = $a->selectSingleNode('//c');

echo 'content: ', $c->textContent;

class nDOMElement extends DOMElement {
  public function selectNodes($xpath){
    $oxpath = new DOMXPath($this->ownerDocument);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}


class nDOMDocument extends DOMDocument {
  public function __construct($version=NULL, $encoding=NULL) {
    parent::__construct($version, $encoding);
    $this->registerNodeClass('DOMElement', 'nDOMElement');
  }

  public function selectNodes($xpath){
    $oxpath = new DOMXPath($this);
    return $oxpath->query($xpath);
  }
  public function selectSingleNode($xpath){
    return $this->selectNodes($xpath)->item(0);
  }
}

印刷しcontent: fooます。

registerNodeClass('DOMNode', 'MyDOMNode')ただし、今後DOMElementがDOMNodeではなくMyDOMNodeから継承するように設定して期待することはできません。つまり、上書きするすべてのノードタイプを登録する必要があります。

于 2010-04-06T20:49:01.800 に答える
1

ここでは、既存のライブラリを直接サブクラス化するのではなく、ラッパー オブジェクトで装飾する方がよいと思います。既におわかりのように、ヘルパー メソッドを簡単に追加しDOMDocumentて、サブクラス化されたオブジェクトを返させることはできません。

具体的には、ここでの問題は、DOMXPath::item()が を返すことを認識していないことnDOMNodeです。

次のようなことをしようとすると、失敗します (多くのプロパティが読み取り専用のように見えます)。

class nDOMDocument extends DOMDocument {

    ...

    public function selectSingleNode($xPath) {
        $node = $this->selectNodes($xPath)->item(0);
        $myNode = new nDOMNode;
        $myNode->set_name($node->get_name()); // fail?
        $myNode->set_content($node->get_content());
        // set namespace
        // can you set the owner document? etc

        return $myNode;
    }

}

代わりにオブジェクトをラップすると、__get()および__call() 魔法のメソッドを使用して既存の DOMNode インターフェイスをすばやく公開し、追加の機能を含めて、独自のラップされた/カスタム クラスを返すことを選択して、元の目標を達成できます。

例:

class nDOMNode {

    protected $_node;

    public function __construct(DOMNode $node) {
        $this->_node = $node;
    }

    // your methods

}

class nDOMDocument {

    protected $_doc;

    public function __construct(DOMDocument $doc) {
        $this->_doc = $doc;
    }

    ...

    public function selectNodes($xPath){
        $oxPath = new DOMXPath($this->_doc->ownerDocument, $this->_doc);
        return $oxPath->query($xPath);
    }

    public function selectSingleNode($xPath) {
        return new nDOMNode($this->selectNodes($xPath)->item(0));
    }

}

$doc = new nDOMDocument(new DOMDocument);
$doc->loadXML('<xml>');
$node = $doc->selectSingleNode("//item[@id=2]"); // returns nDOMNode

お役に立てれば。

于 2010-04-06T16:29:53.190 に答える
1

nDOMDocument::selectSingleNode() をコーディングして nDOMNode オブジェクトを返す必要があります。起こり得る魔法の変換はありません。

途中でいくつかの優れた OOP の教訓を学ぶことができるので、実験を続ける必要があります (難しい方法ではありますが)。それは何も悪いことではありません。

于 2010-04-06T15:10:24.627 に答える
1

オブジェクト指向アプローチの結果の 1 つは、継承が一方通行であることです。つまり、子のメソッドを親に知らせる方法はありません。したがって、オブジェクトのコレクションを反復処理することはできますが、確実に呼び出すことができるのは親クラスのメソッドのみです。PHP には実行時にメソッドが存在するかどうかをテストする方法があり、これは便利ですが、すぐに見苦しくなります。

つまり、組み込みクラスを拡張する場合は、完全に拡張して、アプリケーションが組み込みクラスのインスタンスで動作しないようにする必要があります。つまり、バージョンのみを使用します。あなたの場合、拡張クラスを展開して、親のクラス型を返すすべての親のメソッドをオーバーライドする必要があります。

public myClass extends foo {
// override all methods that would normally return foo objects so that they
// return myClass objects.
}
于 2010-04-06T16:22:07.870 に答える
0

ここでは、DOMがJavaScriptに対して行うように、ここで長い道のりを歩き、下、上、左、右を指すポインティングプロパティをインストールする必要があると思います。これらは、構造を作成するときに必ず割り当てられます。

于 2010-04-06T15:14:24.693 に答える