$list = array('br', 'hr', 'link', 'meta', 'title');
DOMXpath を使用して、空であり、tagName が $list 内にないノードを選択するにはどうすればよいですか? textContent
(自動的に閉じないようにスペースを追加したい)
以下は、必要なノードを選択する単一のワンライナー XPath 式です。
//*[not(node()[not(self::text())])
and not(normalize-space)
and contains('|br|hr|link|meta|title|', concat('|', name(), '|'))
]
これにより、テキスト ノードの子 (存在する場合) のみを持ち、正規化された (先頭と末尾のすべての空白文字が削除され、中間の隣接するすべての空白文字が単一のスペースに置き換えられた) 文字列を持つ XML ドキュメント内の要素が選択されます。 value は空の文字列で、その名前はbr
、hr
、meta
またはのいずれか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 ©
<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/>
作業する 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()
代わりに使用できます。
XpathエンジンはPHP変数にアクセスできません。リストを有効なXpath式として引用するか、PHPでdomノードをフィルター処理する必要があります。PHPマニュアルでは、フィルターの実装方法について説明しています。http ://www.php.net/manual/en/book.filter.php
同様のタスクを達成するために、次のようなものを使用します。
<?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 ©
<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>';
?>
$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]);
}
}
注:私はそれをテストしませんでした。タイプミスまたは間違ったオブジェクト プロパティがある可能性があります。