2

$list = array('br', 'hr', 'link', 'meta', 'title');

DOMXpath を使用して、空であり、tagName が $list 内にないノードを選択するにはどうすればよいですか? textContent(自動的に閉じないようにスペースを追加したい)

4

5 に答える 5

3

以下は、必要なノードを選択する単一のワンライナー XPath 式です。

//*[not(node()[not(self::text())]) 
  and not(normalize-space) 
  and contains('|br|hr|link|meta|title|', concat('|', name(), '|'))
   ]

これにより、テキスト ノードの子 (存在する場合) のみを持ち、正規化された (先頭と末尾のすべての空白文字が削除され、中間の隣接するすべての空白文字が単一のスペースに置き換えられた) 文字列を持つ XML ドキュメント内の要素が選択されます。 value は空の文字列で、その名前はbrhrmetaまたはのいずれかtitleです。

XSLT ベースの検証:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>


  <xsl:template match="/">
   <xsl:copy-of select=
   "//*[not(node()[not(self::text())])
      and not(normalize-space)
      and contains('|br|hr|link|meta|title|', concat('|', name(), '|'))
       ]
   "/>
  </xsl:template>
</xsl:stylesheet>

この変換が次の XML ドキュメントに適用される場合:

<html lang='en'>
    <head>
        <meta charset='utf-8'/>
        <title></title>
        <link rel='stylesheet' href='/assets/index.css'/>
    </head>
    <body>
        <div>
            <header>
                <h1></h1>
            </header>
            <section>
                <article></article>
                <aside></aside>
            </section>
            <br />
            <footer>
                <small>
                 Copyright &#169;
                    <span></span>
                </small>
            </footer>
        </div>
        <script src='//code.jquery.com/jquery-latest.min.js'></script>
        <script src='/assets/index.js'></script>
    </body>
</html>

XPath 式が評価され、(正しく) 選択されたノードが出力にコピーされます。

<meta charset="utf-8"/>
<title/>
<link rel="stylesheet" href="/assets/index.css"/>
<br/>
于 2012-05-31T02:37:22.810 に答える
3

作業する XML が提供されていませんが、これはあまり良くありません。

$xml = <<<XML
<div>
   <a>
   </a>
   <p>some text</p>
   <p></p>
   <span>no text
      <hr/>
      <ul></ul>
   </span>
   <br/>
</div>
XML;

$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$list = array('br', 'hr', 'link', 'meta', 'title');
$expr = array();
foreach ($list as $l) {
   $expr[] = "not(self::$l)";
}
$expr = implode(' and ', $expr);

foreach ($xpath->query("//*[$expr and not(normalize-space())]") as $elem) {
   echo "$elem->nodeName\n";
}

これは出力します

a
p
ul

予想通り。これでノードができました。スペースを追加するのはあなた次第です。IMO を使用して、リストにないnot(normalize-space())かどうかを確認する方が簡単ですが、XPath 式を要求したので、それが得られました。nodeName

が使用されていることに注意してください。これnormalize-space()は、純粋な空白でもノードが自動的に閉じられる可能性があるためです。それが問題でない場合は、node()代わりに使用できます。

于 2012-05-30T14:40:56.417 に答える
1

XpathエンジンはPHP変数にアクセスできません。リストを有効なXpath式として引用するか、PHPでdomノードをフィルター処理する必要があります。PHPマニュアルでは、フィルターの実装方法について説明しています。http ://www.php.net/manual/en/book.filter.php

于 2012-05-30T14:46:13.740 に答える
1

同様のタスクを達成するために、次のようなものを使用します。

<?php
$xml = <<<XML
<html lang='en'>
  <head>
    <meta charset='utf-8'/>
    <title></title>
    <link rel='stylesheet' href='/assets/index.css'/>
  </head>
  <body>
    <div>
      <header>
        <h1></h1>
      </header>
      <section>
        <article></article>
        <aside></aside>
      </section>
      <footer>
        <small>
          Copyright &#169;
          <span></span>
        </small>
      </footer>
    </div>
    <script src='//code.jquery.com/jquery-latest.min.js'></script>
    <script src='/assets/index.js'></script>
  </body>
</html>
XML;
$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$null = array( 'br','hr','meta','link','base','link','meta','img'
             , 'embed','param','area','col','input' );
array_walk($null, function(&$v){$v = "not(self::{$v})";});
array_unshift($null, 'not(normalize-space())');
$null = implode(' and ', $null);
$node = $xpath->query("//*[{$null}]");

$collapsed = htmlspecialchars($dom->saveXML($dom->documentElement));
foreach ($node as $n) $n->appendChild($dom->createTextNode(''));
$separated = htmlspecialchars($dom->saveXML($dom->documentElement));

echo '<pre>', $collapsed, '<hr/>', $separated, '</pre>';
?>
于 2012-05-31T00:04:50.147 に答える
1
$doc = new DOMDocument();
$doc->loadHTMLFile($file);
$xpath = new DOMXpath($doc);

$list = array('br', 'hr', 'link', 'meta', 'title');
$empty_items = $xpath->query("//*[not(text())]");
foreach($empty_items as $key=>$element){
    if(is_object($element) &&
       get_class($element) == 'DOMElement' &&
       in_array($element->nodeName,$list)){
        unset($empty_items[$key]);
    }
}

注:私はそれをテストしませんでした。タイプミスまたは間違ったオブジェクト プロパティがある可能性があります。

于 2012-05-30T14:38:55.157 に答える