बिना HTML आवरण के DOMDocument के HTML को कैसे बचाया जाए?


116

मैं नीचे फ़ंक्शन कर रहा हूं, मैं सामग्री के आउटपुट से पहले एक्सएमडी , HTML, बॉडी और पी टैग रैपर को जोड़ने के बिना DOMDocument के आउटपुट के लिए संघर्ष कर रहा हूं । सुझाया गया फिक्स:

$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));

केवल तभी काम करता है जब सामग्री में कोई ब्लॉक स्तर के तत्व नहीं होते हैं। हालाँकि, जब ऐसा होता है, जैसा कि नीचे दिए गए उदाहरण में h1 तत्व के साथ होता है, तो saveXML से परिणामी आउटपुट को काट दिया जाता है ...

<p> अगर आपको पसंद है </ p>

मुझे इस पद के लिए एक संभावित समाधान के रूप में इंगित किया गया है, लेकिन मैं यह नहीं समझ सकता कि इसे इस समाधान में कैसे लागू किया जाए (नीचे दिए गए प्रयासों को देखें)।

कोई सुझाव?

function rseo_decorate_keyword($postarray) {
    global $post;
    $keyword = "Jasmine Tea"
    $content = "If you like <h1>jasmine tea</h1> you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea."
    $d = new DOMDocument();
    @$d->loadHTML($content);
    $x = new DOMXpath($d);
    $count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])");
    if ($count > 0) return $postarray;
    $nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h1) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]");
    if ($nodes && $nodes->length) {
        $node = $nodes->item(0);
        // Split just before the keyword
        $keynode = $node->splitText(strpos($node->textContent, $keyword));
        // Split after the keyword
        $node->nextSibling->splitText(strlen($keyword));
        // Replace keyword with <b>keyword</b>
        $replacement = $d->createElement('strong', $keynode->textContent);
        $keynode->parentNode->replaceChild($replacement, $keynode);
    }
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes);
return $postarray;
}

जवाबों:


217

ये सभी उत्तर अब गलत हैं , क्योंकि PHP 5.4 और Libxml 2.6 के रूप में loadHTMLअब एक $optionपैरामीटर है जो Libxml को निर्देश देता है कि इसे सामग्री को कैसे पार्स करना चाहिए।

इसलिए, यदि हम इन विकल्पों के साथ HTML लोड करते हैं

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

जब saveHTML()वहाँ कोई नहीं doctype, नहीं <html>, और नहीं होगा <body>

LIBXML_HTML_NOIMPLIEDनिहित HTML / शरीर तत्वों के स्वत: जोड़ने को बंद कर देता है LIBXML_HTML_NODEFDTDजब कोई नहीं पाया जाता है तो एक डिफ़ॉल्ट सिद्धांत को जोड़ा जाता है।

Libxml मापदंडों के बारे में पूर्ण प्रलेखन यहाँ है

(ध्यान दें कि loadHTMLडॉक्स का कहना है कि Libxml 2.6 की आवश्यकता है, लेकिन LIBXML_HTML_NODEFDTDकेवल Libxml 2.7.8 LIBXML_HTML_NOIMPLIEDमें उपलब्ध है और Libxml 2.7.7 में उपलब्ध है)


10
यह एक आकर्षण की तरह काम करता है। स्वीकृत उत्तर होना चाहिए। मैंने सिर्फ एक ध्वज जोड़ा और मेरे सभी सिर दर्द दूर हो गए;;
बस प्लेन हाई

8
यह PHP 5.4 और Libxml 2.9 के साथ काम नहीं करता है। loadHTML किसी भी विकल्प को स्वीकार नहीं करता है :(
Acyra

11
ध्यान दें कि यह बिल्कुल सही नहीं है। देखें stackoverflow.com/questions/29493678/...
जोश लेविनसन

4
क्षमा करें, लेकिन यह बिल्कुल अच्छा समाधान नहीं है (कम से कम व्यवहार में नहीं है)। यह वास्तव में स्वीकृत उत्तर नहीं होना चाहिए। उल्लेख किया मुद्दों के अलावा, वहाँ भी एक है बुरा एन्कोडिंग मुद्दे के साथ DOMDocumentवह भी इस जवाब में कोड प्रभावित करता है। Afaik, DOMDocumentहमेशा इनपुट डेटा को लैटिन -1 के रूप में व्याख्या करता है जब तक कि इनपुट एक अलग चार्ट को निर्दिष्ट नहीं करता है । दूसरे शब्दों में: <meta charset="…">टैग इनपुट डेटा के लिए आवश्यक है जो कि लैटिन -1 नहीं है। अन्यथा आउटपुट UTF-8 मल्टीबाइट पात्रों के लिए तोड़ा जाएगा।
मर्माहॉस

1
LIBXML_HTML_NOIMPLIED टैब, इंडेंट और लाइन ब्रेक को हटाकर HTML कोड को भी गड़बड़ करता है
Zoltán Süle

72

लोड किए गए दस्तावेज़ को लोड करने के बाद सीधे नोड्स निकालें ():

# remove <!DOCTYPE 
$doc->removeChild($doc->doctype);           

# remove <html><body></body></html> 
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

यह मेरे लिए क्लीनर जवाब है।
19

39
यह ध्यान दिया जाना चाहिए कि यह काम करता है यदि <body> में केवल एक बच्चा नोड है।
यन मिलिन

बढ़िया काम किया। धन्यवाद! अन्य प्राग उत्तर की तुलना में बहुत साफ और तेज।
22

इसके लिए शुक्रिया! मैंने खाली नोड्स को संभालने के लिए नीचे एक और स्निप जोड़ा।
redaxmedia

2
<!DOCTYPE कार्यों को हटाने के लिए कोड । यदि <body>एक से अधिक चाइल्ड नोट हैं, तो दूसरी पंक्ति टूट जाती है ।
नि: शुल्क कट्टरपंथी

21

saveXML()इसके बजाय का उपयोग करें , और एक तर्क के रूप में डॉक्यूमेंटमेंट पास करें।

$innerHTML = '';
foreach ($document->getElementsByTagName('p')->item(0)->childNodes as $child) {
    $innerHTML .= $document->saveXML($child);
}
echo $innerHTML;

http://php.net/domdocument.savexml


यह बेहतर है, लेकिन मैं अभी भी <html> <body> <p> सामग्री लपेट रहा हूं।
स्कॉट बी


2
यह ध्यान दिया जाना चाहिए कि saveXML () HTML को नहीं, XHTML को बचाएगा।
21

@ सच: यह वाकई अजीब है। यह दिखाता है कि आप उदाहरण अनुभाग में वहीं करने की कोशिश कर रहे हैं। क्या आप सुनिश्चित हैं कि आपके DOM में HTML नहीं है? वास्तव में HTML आपके DOMDocument में क्या है? यह हो सकता है कि हमें एक बच्चे के नोड तक पहुंचने की आवश्यकता है।
योना

@ जनाब यह अजीब नहीं है। जब आप loadHTMLlibxml HTML parser मॉड्यूल का उपयोग करते हैं और वह गुम HTML कंकाल डाल देगा। नतीजतन, $dom->documentElementरूट HTML तत्व होगा। मैंने आपका उदाहरण कोड तय कर दिया है। अब यह करना चाहिए कि स्कॉट क्या पूछ रहा है।
गॉर्डन

19

शीर्ष उत्तर के साथ मुद्दा यह है कि LIBXML_HTML_NOIMPLIEDअस्थिर है

यह तत्वों को पुन: व्यवस्थित कर सकता है (विशेष रूप से, दस्तावेज़ के निचले भाग में शीर्ष तत्व के समापन टैग को आगे बढ़ाते हुए), यादृच्छिक pटैग और शायद अन्य मुद्दों की एक किस्म [1] जोड़ें । यह आपके लिए htmlऔर bodyटैग हटा सकता है , लेकिन अस्थिर व्यवहार की कीमत पर। उत्पादन में, यह एक लाल झंडा है। संक्षेप में:

उपयोग न करेंLIBXML_HTML_NOIMPLIEDइसके बजाय, उपयोग करेंsubstr


इसके बारे में सोचो। दस्तावेज़ के दोनों सिरों पर लंबाई <html><body>और </body></html>निश्चित होती है - उनके आकार कभी नहीं बदलते हैं, और न ही उनके स्थान। यह हमें substrउन्हें दूर करने के लिए उपयोग करने की अनुमति देता है:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

echo substr($dom->saveHTML(), 12, -15); // the star of this operation

( यह अंतिम हल नहीं है! पूरा जवाब के लिए नीचे देखें! संदर्भ के लिए पढ़ते रहें)

हमने 12दस्तावेज़ की शुरुआत से दूर काट दिया क्योंकि <html><body>= 12 अक्षर ( <<>>+html+body= 4 + 4 + 4), और हम पीछे की ओर जाते हैं और अंत में 15 को काटते हैं क्योंकि \n</body></html>= 15 वर्ण ( \n+//+<<>>+body+html= 1 + 2 + 4 + 4 + 4)

ध्यान दें कि मैं अभी भी शामिल होने से LIBXML_HTML_NODEFDTDचूक का उपयोग करता हूं !DOCTYPE। सबसे पहले, यह substrHTML / BODY टैग को हटाने को सरल बनाता है। दूसरा, हम इस सिद्धांत को नहीं हटाते substrक्योंकि हम नहीं जानते कि ' default doctype' हमेशा एक निश्चित लंबाई का कुछ होगा। लेकिन, सबसे महत्वपूर्ण बात LIBXML_HTML_NODEFDTDयह है कि डॉम पार्सर को दस्तावेज़ में एक गैर-एचटीएमएल 5 सिद्धांत लागू करने से रोकता है - जो कम से कम पार्सर को उन तत्वों के उपचार से रोकता है जो इसे ढीले पाठ के रूप में नहीं पहचानता है।

हम इस तथ्य के लिए जानते हैं कि HTML / BODY टैग निश्चित लंबाई और स्थिति के होते हैं, और हम जानते हैं कि स्थिरांक LIBXML_HTML_NODEFDTDको किसी प्रकार के अपचयन सूचना के बिना कभी नहीं हटाया जाता है, इसलिए उपरोक्त विधि को भविष्य में अच्छी तरह से रोल करना चाहिए, लेकिन ...


... केवल चेतावनी यह है कि DOM कार्यान्वयन HTML / BODY टैग्स के तरीके को दस्तावेज़ के भीतर बदल सकता है - उदाहरण के लिए, दस्तावेज़ के अंत में नई पंक्ति को हटाकर, टैग के बीच रिक्त स्थान जोड़कर या newlines जोड़कर।

इसके लिए खुलने और बंद होने वाले टैगों की स्थिति की खोज bodyकरके, और उन ऑफसेट्स का उपयोग करके हमारी लंबाई के हिसाब से ट्रिम कर दिया जा सकता है। हम का उपयोग करें strposऔर strrposआगे और पीछे से क्रमशः ऑफसेट खोजने के लिए:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
// PositionOf<body> + 6 = Cutoff offset after '<body>'
// 6 = Length of '<body>'

$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());
// ^ PositionOf</body> - LengthOfDocument = Relative-negative cutoff offset before '</body>'

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

समापन में, फाइनल का दोहराव, भविष्य के सबूत का जवाब :

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

कोई सिद्धांत नहीं, कोई html टैग नहीं, कोई बॉडी टैग नहीं। हम केवल यह आशा कर सकते हैं कि DOM पार्सर जल्द ही पेंट का एक नया कोट प्राप्त करेगा और हम इन अवांछित टैगों को और अधिक सीधे समाप्त कर सकते हैं।


शानदार जवाब, एक छोटी सी टिप्पणी, बार-बार के $html = $dom -> saveHTML();बजाय क्यों $dom -> saveHTML();?
स्टीवन

15

एक साफ-सुथरी चाल का उपयोग करना है loadXMLऔर फिर saveHTMLhtmlऔर bodyटैग पर डाला जाता है loadचरण, नहीं saveमंच।

$dom = new DOMDocument;
$dom->loadXML('<p>My DOMDocument contents are here</p>');
echo $dom->saveHTML();

एनबी है कि यह थोड़ा हैकरी है और आपको जोनाह के जवाब का उपयोग करना चाहिए यदि आप इसे काम करने के लिए प्राप्त कर सकते हैं।


4
हालांकि यह अमान्य HTML के लिए विफल हो जाएगा।
गॉर्डन

1
@Gordon बिल्कुल क्यों मैं नीचे में अस्वीकरण डाल दिया!
lonesomeday

1
जब मैं यह कोशिश करता हूं, और $ डोम-> saveHTML () को गूँजता हूं, तो यह एक खाली स्ट्रिंग देता है। जैसे कि loadXML ($ सामग्री) खाली है। जब मैं $ डोम-> लोड HTML ($ सामग्री) के साथ ऐसा करता हूं, तो $ डोम-> saveXML () की अपेक्षा के अनुसार सामग्री प्राप्त करता हूं।
स्कॉट बी

लोडएक्सएमएल का उपयोग करते समय एचटीएमएल को लोड करने के लिए तैयार अंगूठे। विशेष रूप से क्योंकि LoadXML को नहीं पता है कि HTML को कैसे संभालना है।
बोटनवॉवर

15

DOMDocumentFragment का उपयोग करें

$html = 'what you want';
$doc = new DomDocument();
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($html);
$doc->appendChild($fragment);
echo $doc->saveHTML();

3
पूर्व php5.4 के लिए सबसे साफ जवाब।
निक जॉनसन

यह मेरे लिए काम करता है, दोनों पुराने और लिबक्सएमएल संस्करण 2.7.7 से नए हैं। यह पूरी तरह से पूर्व php5.4 के लिए क्यों होगा?
रोबर्ट टीटी

इसके लिए अधिक वोट होने चाहिए। Libxml के संस्करणों के लिए बढ़िया विकल्प जो LIBXML_HTML_NOIMPLIED का समर्थन नहीं करता है LIBXML_HTML_NODEFDTD। धन्यवाद!
मार्टी मुलिगन

13

यह 2017 है, और इस 2011 के प्रश्न के लिए मुझे कोई जवाब पसंद नहीं है। रेगेक्स, बड़ी कक्षाओं, loadXML आदि के बहुत सारे ...

आसान समाधान जो ज्ञात समस्याओं को हल करता है:

$dom = new DOMDocument();
$dom->loadHTML( '<html><body>'.mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8').'</body></html>' , LIBXML_HTML_NODEFDTD);
$html = substr(trim($dom->saveHTML()),12,-14);

आसान, सरल, ठोस, तेज। यह कोड HTML टैग और एन्कोडिंग जैसे काम करेगा:

$html = '<p>äöü</p><p>ß</p>';

अगर किसी को कोई त्रुटि मिलती है, तो कृपया बताएं, मैं खुद इसका उपयोग करूंगा।

संपादित करें , अन्य वैध विकल्प जो त्रुटियों के बिना काम करते हैं (पहले से दिए गए समान हैं):

@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$saved_dom = trim($dom->saveHTML());
$start_dom = stripos($saved_dom,'<body>')+6;
$html = substr($saved_dom,$start_dom,strripos($saved_dom,'</body>') - $start_dom );

आप किसी भी अजीब चीज को रोकने के लिए खुद को शरीर से जोड़ सकते हैं।

बेहतर विकल्प:

 $mock = new DOMDocument;
 $body = $dom->getElementsByTagName('body')->item(0);
  foreach ($body->childNodes as $child){
     $mock->appendChild($mock->importNode($child, true));
  }
$html = trim($mock->saveHTML());

3
आपको अधिक महंगे से बचने और तदनुसार mb_convert_encodingजोड़ने <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>और संशोधित करने के द्वारा अपने उत्तर में सुधार करना चाहिए substr। Btw, तुम्हारा सबसे सुरुचिपूर्ण समाधान यहाँ है। Upvoted।
Hlsg

10

मैं थोड़ा क्लब में देर हो रही है, लेकिन नहीं करना चाहता था नहीं एक विधि मैं बारे में पता चला गया है सकते हैं। सबसे पहले मुझे इन अच्छे विकल्पों को स्वीकार करने के लिए loadHTML () के लिए सही संस्करण मिले हैं, लेकिन LIBXML_HTML_NOIMPLIEDमेरे सिस्टम पर काम नहीं किया। साथ ही उपयोगकर्ता पार्सर के साथ समस्याओं की रिपोर्ट करते हैं (उदाहरण के लिए यहां और यहां )।

मैं वास्तव में बनाया समाधान बहुत आसान है।

लोड किए जाने वाले HTML में डाल दिया जाता है <div> तत्व ताकि इसमें एक कंटेनर हो, जिसमें सभी नोड लोड किए जा सकें।

तो फिर इस कंटेनर तत्व दस्तावेज़ (लेकिन से निकाल दिया जाता DOMElement की यह अभी भी मौजूद है)।

फिर दस्तावेज़ से सभी प्रत्यक्ष बच्चों को हटा दिया जाता है। इसमें कोई जोड़ा <html>, <head>और <body>टैग (प्रभावी रूप से LIBXML_HTML_NOIMPLIEDविकल्प) के साथ-साथ <!DOCTYPE html ... loose.dtd">घोषणा (प्रभावी रूप से LIBXML_HTML_NODEFDTD) शामिल हैं।

फिर कंटेनर के सभी प्रत्यक्ष बच्चों को फिर से दस्तावेज़ में जोड़ा जाता है और यह आउटपुट हो सकता है।

$str = '<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>';

$doc = new DOMDocument();

$doc->loadHTML("<div>$str</div>");

$container = $doc->getElementsByTagName('div')->item(0);

$container = $container->parentNode->removeChild($container);

while ($doc->firstChild) {
    $doc->removeChild($doc->firstChild);
}

while ($container->firstChild ) {
    $doc->appendChild($container->firstChild);
}

$htmlFragment = $doc->saveHTML();

XPath हमेशा की तरह काम करता है, बस ध्यान रखें कि अब कई दस्तावेज़ तत्व हैं, इसलिए एक रूट नोड नहीं:

$xpath = new DOMXPath($doc);
foreach ($xpath->query('/p') as $element)
{   #                   ^- note the single slash "/"
    # ... each of the two <p> element

  • PHP 5.4.36-1 + deb.sury.org ~ सटीक + 2 (cli) (निर्मित: 21 दिसंबर 2014 20:28:53)

यह मेरे लिए अधिक जटिल HTML स्रोत के साथ काम नहीं किया। इसने HTML का दिया हुआ भाग भी निकाल दिया।
ज़ोल्टन सुले

4

इस लेखन के समय (जून, 2012) कोई भी अन्य समाधान पूरी तरह से मेरी जरूरतों को पूरा करने में सक्षम नहीं था, इसलिए मैंने एक लिखा जो निम्नलिखित मामलों को संभालता है:

  • सादे-पाठ सामग्री को स्वीकार करता है जिसमें कोई टैग नहीं है, साथ ही साथ HTML सामग्री भी।
  • किसी भी टैग संलग्न नहीं है (सहित <doctype>, <xml>, <html>, <body>, और <p>टैग)
  • <p>अकेले में लिपटे हुए कुछ भी छोड़ देता है।
  • खाली पाठ अकेला छोड़ देता है।

तो यहाँ एक समाधान है जो उन मुद्दों को हल करता है:

class DOMDocumentWorkaround
{
    /**
     * Convert a string which may have HTML components into a DOMDocument instance.
     *
     * @param string $html - The HTML text to turn into a string.
     * @return \DOMDocument - A DOMDocument created from the given html.
     */
    public static function getDomDocumentFromHtml($html)
    {
        $domDocument = new DOMDocument();

        // Wrap the HTML in <div> tags because loadXML expects everything to be within some kind of tag.
        // LIBXML_NOERROR and LIBXML_NOWARNING mean this will fail silently and return an empty DOMDocument if it fails.
        $domDocument->loadXML('<div>' . $html . '</div>', LIBXML_NOERROR | LIBXML_NOWARNING);

        return $domDocument;
    }

    /**
     * Convert a DOMDocument back into an HTML string, which is reasonably close to what we started with.
     *
     * @param \DOMDocument $domDocument
     * @return string - The resulting HTML string
     */
    public static function getHtmlFromDomDocument($domDocument)
    {
        // Convert the DOMDocument back to a string.
        $xml = $domDocument->saveXML();

        // Strip out the XML declaration, if one exists
        $xmlDeclaration = "<?xml version=\"1.0\"?>\n";
        if (substr($xml, 0, strlen($xmlDeclaration)) == $xmlDeclaration) {
            $xml = substr($xml, strlen($xmlDeclaration));
        }

        // If the original HTML was empty, loadXML collapses our <div></div> into <div/>. Remove it.
        if ($xml == "<div/>\n") {
            $xml = '';
        }
        else {
            // Remove the opening <div> tag we previously added, if it exists.
            $openDivTag = "<div>";
            if (substr($xml, 0, strlen($openDivTag)) == $openDivTag) {
                $xml = substr($xml, strlen($openDivTag));
            }

            // Remove the closing </div> tag we previously added, if it exists.
            $closeDivTag = "</div>\n";
            $closeChunk = substr($xml, -strlen($closeDivTag));
            if ($closeChunk == $closeDivTag) {
                $xml = substr($xml, 0, -strlen($closeDivTag));
            }
        }

        return $xml;
    }
}

मैंने कुछ परीक्षण भी लिखे जो उसी कक्षा में रहेंगे:

public static function testHtmlToDomConversions($content)
{
    // test that converting the $content to a DOMDocument and back does not change the HTML
    if ($content !== self::getHtmlFromDomDocument(self::getDomDocumentFromHtml($content))) {
        echo "Failed\n";
    }
    else {
        echo "Succeeded\n";
    }
}

public static function testAll()
{
    self::testHtmlToDomConversions('<p>Here is some sample text</p>');
    self::testHtmlToDomConversions('<div>Lots of <div>nested <div>divs</div></div></div>');
    self::testHtmlToDomConversions('Normal Text');
    self::testHtmlToDomConversions(''); //empty
}

आप जांच सकते हैं कि यह आपके लिए काम करता है। DomDocumentWorkaround::testAll()यह रिटर्न:

    Succeeded
    Succeeded
    Succeeded
    Succeeded

1
HTML = / = XML, आपको HTML के लिए HTML लोडर का उपयोग करना चाहिए।
हकर्रे

4

ठीक है मुझे एक और अधिक सुंदर समाधान मिला, लेकिन यह सिर्फ थकाऊ है:

$d = new DOMDocument();
@$d->loadHTML($yourcontent);
...
// do your manipulation, processing, etc of it blah blah blah
...
// then to save, do this
$x = new DOMXPath($d);
$everything = $x->query("body/*"); // retrieves all elements inside body tag
if ($everything->length > 0) { // check if it retrieved anything in there
      $output = '';
      foreach ($everything as $thing) {
           $output .= $d->saveXML($thing);
      }
      echo $output; // voila, no more annoying html wrappers or body tag
}

ठीक है, उम्मीद है कि यह कुछ भी नहीं छोड़ता है और किसी की मदद करता है?



3

इस फ़ंक्शन का उपयोग करें

$layout = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $layout);

13
कुछ पाठकों को के माध्यम से इस पोस्ट भर में ठोकर खाई है हो सकता है इस पोस्ट , अपने HTML पार्स और इसके बजाय एक डोम पार्सर का उपयोग, और संभवतः एक regex जवाब की आवश्यकता होगी, एक पूर्ण समाधान ... विडंबना प्राप्त करने के लिए अंत करने के लिए उपयोग regex नहीं करने का फैसला किया है
रोबी एवेरिल

मुझे समझ नहीं आ रहा है कि क्यों noboy सिर्फ BODY की सामग्री लौटाता है। क्या उस टैग को हमेशा मौजूद नहीं माना जाता है जब पार्सर पूरे दस्तावेज़ हेडर / सिद्धांत को जोड़ता है? ऊपर रेगेक्स भी छोटा होगा।
सर्जियो

@boksiora "यह काम करता है" - तो फिर हम पहले स्थान पर DOM पार्सर विधियों का उपयोग क्यों कर रहे हैं?
धन्यवाद

@naomik मैंने डोम पार्सर का उपयोग नहीं करने के लिए नहीं कहा है, निश्चित रूप से एक ही परिणाम प्राप्त करने के लिए कई अलग-अलग तरीके हैं, इसके ऊपर, आपके द्वारा इस फ़ंक्शन का उपयोग करने पर मुझे अंतर्निहित php डोम के साथ एक समस्या थी पार्सर, जो html5 को सही ढंग से पार्स नहीं कर रहा था।
boksiora

1
मुझे प्रयोग करना पड़ा preg_replaceक्योंकि html और बॉडी टैग हटाने के DOMDocument- आधारित तरीकों का उपयोग करके UTF-8 एन्कोडिंग को संरक्षित नहीं किया गया था :(
wizonesolutions

3

यदि Alessandro Vendruscolo द्वारा दिए गए झंडे समाधान काम नहीं करता है, तो आप यह कोशिश कर सकते हैं:

$dom = new DOMDocument();
$dom->loadHTML($content);

//do your stuff..

$finalHtml = '';
$bodyTag = $dom->documentElement->getElementsByTagName('body')->item(0);
foreach ($bodyTag->childNodes as $rootLevelTag) {
    $finalHtml .= $dom->saveHTML($rootLevelTag);
}
echo $finalHtml;

$bodyTag उन सभी HTML रैप के बिना आपका पूर्ण संसाधित HTML कोड होगा, सिवाय पूर्ण के <body>टैग के , जो आपकी सामग्री का मूल है। फिर आप इसे अंतिम स्ट्रिंग (बाद में saveHTML) से हटाने के लिए एक रेगेक्स या ट्रिम फ़ंक्शन का उपयोग कर सकते हैं या, जैसे कि ऊपर के मामले में, अपने सभी बच्चों पर पुनरावृति कर सकते हैं, उनकी सामग्री को एक अस्थायी चर में सहेज सकते हैं $finalHtmlऔर इसे वापस कर सकते हैं (मुझे विश्वास है कि क्या हो रहा है) सुरक्षित)।


3

मैं RHEL7 पर PHP 5.6.25 और LibXML 2.9 चलाने पर इससे जूझ रहा हूं। (पुरानी सामग्री 2018 में, मुझे पता है, लेकिन यह आपके लिए Red Hat है।)

मैंने पाया है कि Alessandro Vendruscolo द्वारा सुझाए गए बहुत अधिक उत्कीर्ण समाधान टैग को रीक्रिएट करके HTML को तोड़ते हैं। अर्थात:

<p>First.</p><p>Second.</p>'

हो जाता है:

<p>First.<p>Second.</p></p>'

यह आपके द्वारा उपयोग किए जाने वाले दोनों विकल्पों के लिए जाता है: LIBXML_HTML_NOIMPLIEDऔर LIBXML_HTML_NODEFDTD

एलेक्स द्वारा सुझाए गए समाधान को हल करने के लिए आधा रास्ता जाता है, लेकिन यह काम नहीं करता है यदि <body>एक से अधिक बच्चे नोड हैं।

समाधान है कि मेरे लिए काम करता है follwing है:

पहले, DOMDocument लोड करने के लिए, मैं उपयोग करता हूं:

$doc = new DOMDocument()
$doc->loadHTML($content);

DOMDocument की मालिश करने के बाद दस्तावेज़ को बचाने के लिए, मैं उपयोग करता हूं:

// remove <!DOCTYPE 
$doc->removeChild($doc->doctype);  
$content = $doc->saveHTML();
// remove <html><body></body></html> 
$content = str_replace('<html><body>', '', $content);
$content = str_replace('</body></html>', '', $content);

मैं पहली बार सहमत हूं कि यह एक बहुत ही सुंदर समाधान नहीं है - लेकिन यह काम करता है।


2

<meta>टैग जोड़ने से के फिक्सिंग व्यवहार को ट्रिगर किया जाएगाDOMDocument । अच्छी बात यह है कि आपको उस टैग को जोड़ने की आवश्यकता नहीं है। यदि आप अपने चयन के एन्कोडिंग का उपयोग नहीं करना चाहते हैं, तो बस इसे एक निर्माता तर्क के रूप में पास करें।

http://php.net/manual/en/domdocument.construct.php

$doc = new DOMDocument('1.0', 'UTF-8');
$node = $doc->createElement('div', 'Hello World');
$doc->appendChild($node);
echo $doc->saveHTML();

उत्पादन

<div>Hello World</div>

@Bart को धन्यवाद


2

मुझे इसकी आवश्यकता भी थी, और ऊपर एलेक्स द्वारा पोस्ट किए गए समाधान को पसंद किया। कुछ मुद्दे हैं, हालांकि - यदि <body>तत्व में एक से अधिक बच्चे तत्व हैं, तो परिणामस्वरूप दस्तावेज़ में केवल पहला बच्चा तत्व होगा <body>, उनमें से सभी नहीं। इसके अलावा, मुझे चीजों को सशर्त रूप से संभालने के लिए स्ट्रिपिंग की आवश्यकता थी - केवल जब आपके पास HTML शीर्षक के साथ दस्तावेज़ था। इसलिए मैंने इसे इस प्रकार परिष्कृत किया। हटाने के बजाय <body>, मैंने इसे ए में बदल दिया <div>, और एक्सएमएल घोषणा को हटा दिया और <html>

function strip_html_headings($html_doc)
{
    if (is_null($html_doc))
    {
        // might be better to issue an exception, but we silently return
        return;
    }

    // remove <!DOCTYPE 
    if (!is_null($html_doc->firstChild) &&
        $html_doc->firstChild->nodeType == XML_DOCUMENT_TYPE_NODE)
    {
        $html_doc->removeChild($html_doc->firstChild);     
    }

    if (!is_null($html_doc->firstChild) &&
        strtolower($html_doc->firstChild->tagName) == 'html' &&
        !is_null($html_doc->firstChild->firstChild) &&
        strtolower($html_doc->firstChild->firstChild->tagName) == 'body')
    {
        // we have 'html/body' - replace both nodes with a single "div"        
        $div_node = $html_doc->createElement('div');

        // copy all the child nodes of 'body' to 'div'
        foreach ($html_doc->firstChild->firstChild->childNodes as $child)
        {
            // deep copies each child node, with attributes
            $child = $html_doc->importNode($child, true);
            // adds node to 'div''
            $div_node->appendChild($child);
        }

        // replace 'html/body' with 'div'
        $html_doc->removeChild($html_doc->firstChild);
        $html_doc->appendChild($div_node);
    }
}

2

अन्य सदस्यों की तरह, मैंने पहली बार @Alessandro Vendruscolo जवाब की सादगी और भयानक शक्ति में रहस्योद्घाटन किया। निर्माणकर्ता को बस कुछ ध्वजांकित स्थिरांक में पास करने की क्षमता बहुत अच्छी लगती थी। मेरे लिए यह था। मेरे पास LibXML के साथ-साथ PHP दोनों के सही संस्करण हैं, फिर भी कोई फर्क नहीं पड़ता कि यह अभी भी HTML टैग को डॉक्यूमेंट ऑब्जेक्ट के नोड स्ट्रक्चर में जोड़ देगा।

मेरे समाधान ने बेहतर तरीके से काम किया ...

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

झंडे या ...।

# remove <!DOCTYPE 
$doc->removeChild($doc->firstChild);            

# remove <html><body></body></html>
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

एनओडी हटाने, जो डोम में संरचित आदेश के बिना गड़बड़ हो जाता है। फिर से कोड के टुकड़ों में पूर्व निर्धारित डोम संरचना का कोई रास्ता नहीं है।

मैंने इस यात्रा की शुरुआत एक आसान तरीका चाहा है जो डोम ट्रैवर्सल को करता है कि कैसे JQuery करता है या कम से कम कुछ फैशन में जो एक संरचित डेटा सेट किया गया था या तो एकल लिंक, दोगुना लिंक या ट्री-नोड नोड ट्रैवर्सल। मुझे परवाह नहीं थी कि जब तक एचटीएमएल करता है मैं एक स्ट्रिंग को पार्स कर सकता हूं और जिस तरह से उपयोग करने के लिए नोड इकाई वर्ग के गुणों की अद्भुत शक्ति है।

अब तक DOMDocument Object ने मुझे चाहा छोड़ दिया है ... जैसा कि कई अन्य प्रोग्रामर के साथ लगता है ... मुझे पता है कि मैंने इस सवाल में बहुत निराशा देखी है क्योंकि मैं अंतिम रूप से .... (लगभग 30 घंटे की कोशिश और असफलता के बाद प्रकार परीक्षण) मुझे यह सब पाने का एक तरीका मिल गया है। मुझे उम्मीद है इससे किसी को सहायता मिलेगी...

सबसे पहले, मैं हर किसी की निंदक हूँ ... योग्य ...

मैं किसी के साथ सहमत होने से पहले एक जीवन भर चला होता कि किसी तीसरे पक्ष के वर्ग को इस उपयोग के मामले में किसी भी तरह की आवश्यकता हो। मैं बहुत ज्यादा था और मैं किसी भी तीसरे पक्ष के वर्ग संरचना का उपयोग करने का प्रशंसक नहीं हूं, हालांकि मैं एक महान पार्सर पर ठोकर खाई। (Google में लगभग ३० बार दिए जाने से पहले मैं अकेला महसूस नहीं करता अगर आप इसे टालते हैं क्योंकि यह किसी भी तरह से अनौपचारिक लग रहा है ...)

यदि आप कोड टुकड़ों का उपयोग कर रहे हैं और आवश्यकता है, तो कोड को किसी भी तरह से पार्सर द्वारा साफ और अप्रभावित किया जाता है, बिना अतिरिक्त टैग का उपयोग किए बिना तो simplePHPParser का उपयोग करें

यह आश्चर्यजनक है और JQuery की तरह काम करता है। मैं अक्सर प्रभावित नहीं हुआ, लेकिन यह वर्ग बहुत सारे अच्छे साधनों का उपयोग करता है और मुझे अभी तक कोई भी त्रुटि नहीं मिली है। मैं यह करने में सक्षम हूं कि यह वर्ग क्या कर सकता है।

आप यहां डाउनलोड करने के लिए इसकी फाइलें , इसके स्टार्टअप निर्देश यहां और इसके एपीआई यहां देख सकते हैं । मैं अत्यधिक अपनी सरल तरीके है कि एक कर सकते हैं के साथ इस वर्ग के उपयोग करने की अनुशंसा .find(".className")उसी तरह एक JQuery खोज विधि का इस्तेमाल किया जाएगा या इस तरह के रूप भी परिचित तरीकों getElementByTagName()या getElementById()...

जब आप इस श्रेणी में एक नोड ट्री को बचाते हैं तो यह कुछ भी नहीं जोड़ता है। आप बस कह सकते हैं $doc->save();और यह पूरे पेड़ को बिना किसी उपद्रव के एक स्ट्रिंग में आउटपुट करता है।

मैं अब भविष्य में सभी गैर-कैप्ड-बैंडविड्थ, परियोजनाओं के लिए इस पार्सर का उपयोग करूंगा।


2

मेरे पास PHP 5.3 है और यहाँ के जवाब मेरे काम नहीं आए।

$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);केवल पहले बच्चे के साथ सभी दस्तावेज को बदल दिया, मेरे पास कई पैराग्राफ थे और केवल पहले को बचाया जा रहा था, लेकिन समाधान ने मुझे कुछ लिखने के बिना कुछ लिखने के लिए एक अच्छा प्रारंभिक बिंदु दिया, मुझे regexपूरा यकीन है कि इसमें सुधार किया जा सकता है लेकिन अगर किसी को भी मेरे लिए एक ही समस्या है यह एक अच्छा प्रारंभिक बिंदु हो सकता है।

function extractDOMContent($doc){
    # remove <!DOCTYPE
    $doc->removeChild($doc->doctype);

    // lets get all children inside the body tag
    foreach ($doc->firstChild->firstChild->childNodes as $k => $v) {
        if($k !== 0){ // don't store the first element since that one will be used to replace the html tag
            $doc->appendChild( clone($v) ); // appending element to the root so we can remove the first element and still have all the others
        }
    }
    // replace the body tag with the first children
    $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
    return $doc;
}

तब हम इसे इस तरह इस्तेमाल कर सकते हैं:

$doc = new DOMDocument();
$doc->encoding = 'UTF-8';
$doc->loadHTML('<p>Some html here</p><p>And more html</p><p>and some html</p>');
$doc = extractDOMContent($doc);

ध्यान दें कि appendChildएक को स्वीकार करता है DOMNodeतो हम नए तत्वों को बनाने की जरूरत नहीं है, हम बस पुन: उपयोग कर सकते हैं जो कि मौजूदा लागू DOMNodeजैसे DOMElementयह जब कई HTML / एक्सएमएल दस्तावेजों से छेड़छाड़ कोड "समझदार" रखने के लिए महत्वपूर्ण हो सकता है


यह केवल एक ही बाल-तत्व के लिए टुकड़ों के लिए काम नहीं करेगा, जिसे आप दस्तावेज़ का पहला बच्चा बनाना चाहते हैं। यह बहुत सीमित है और प्रभावी ढंग से काम नहीं कर रहा है LIBXML_HTML_NOIMPLIEDक्योंकि यह केवल आंशिक रूप से करता है। सिद्धांत को हटाना प्रभावी रूप से है LIBXML_HTML_NODEFDTD
हकरे

2

मैं HTML आवरण को हटाने का तरीका खोजने के लिए इस विषय पर आया था। LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTDकाम करता है महान का उपयोग , लेकिन मैं utf-8 के साथ एक समस्या है। बहुत प्रयास के बाद मुझे एक समाधान मिला। मैं इसे किसी के लिए भी वही समस्या है पोस्ट।

के कारण समस्या हुई <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

समस्या:

$dom = new DOMDocument();
$dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->saveHTML();

समाधान 1:

$dom->loadHTML(mb_convert_encoding($document, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $dom->saveHTML($dom->documentElement));

समाधान 2:

$dom->loadHTML($document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
utf8_decode($dom->saveHTML($dom->documentElement));

1
मुझे यह अच्छा लगता है कि आप अपने निष्कर्षों को साझा करते हैं, लेकिन समाधान 2 पहले से ही यहां सटीक प्रश्नों के साथ मौजूद है और समाधान 1 कहीं और है। समाधान 1 की समस्या के लिए भी दिया गया उत्तर अस्पष्ट है। मैं आपके अच्छे इरादों का सम्मान करता हूं, लेकिन कृपया ध्यान रखें कि यह बहुत शोर पैदा कर सकता है और साथ ही दूसरों को उन समाधानों को खोजने में बाधा उत्पन्न कर सकता है जिनकी वे तलाश कर रहे हैं जो मुझे लगता है कि आप अपने जवाब के साथ प्राप्त करना चाहते हैं। यदि आप एक बार में एक प्रश्न को संभालते हैं तो Stackoverflow सबसे अच्छा काम करती है। बस एक संकेत है।
हक्रे

2

मैं DOMDocumentकक्षा के साथ 3 समस्याओं का सामना करता हूं ।

1- यह वर्ग आईएसओ एन्कोडिंग के साथ html लोड करता है और आउटपुट में utf-8 वर्ण नहीं दिखाता है।

2- यहां तक कि अगर हम दे LIBXML_HTML_NOIMPLIEDloadHtml विधि करने के लिए झंडा,

3- यह वर्ग HTML5 टैग को अमान्य मानता है।

इसलिए मैंने इन समस्याओं को हल करने के लिए इस वर्ग को ओवरराइड किया है और मैंने कुछ तरीकों को बदल दिया है।

class DOMEditor extends DOMDocument
{
    /**
     * Temporary wrapper tag , It should be an unusual tag to avoid problems
     */
    protected $tempRoot = 'temproot';

    public function __construct($version = '1.0', $encoding = 'UTF-8')
    {
        //turn off html5 errors
        libxml_use_internal_errors(true);
        parent::__construct($version, $encoding);
    }

    public function loadHTML($source, $options = LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)
    {
        // this is a bitwise check if LIBXML_HTML_NOIMPLIED is set
        if ($options & LIBXML_HTML_NOIMPLIED) {
            // it loads the content with a temporary wrapper tag and utf-8 encoding
            parent::loadHTML("<{$this->tempRoot}>" . mb_convert_encoding($source, 'HTML', 'UTF-8') . "</{$this->tempRoot}>", $options);
        } else {
            // it loads the content with utf-8 encoding and default options
            parent::loadHTML(mb_convert_encoding($source, 'HTML', 'UTF-8'), $options);
        }
    }

    private function unwrapTempRoot($output)
    {
        if ($this->firstChild->nodeName === $this->tempRoot) {
            return substr($output, strlen($this->tempRoot) + 2, -strlen($this->tempRoot) - 4);
        }
        return $output;
    }

    public function saveHTML(DOMNode $node = null)
    {
        $html = html_entity_decode(parent::saveHTML($node));
        if (is_null($node)) {
            $html = $this->unwrapTempRoot($html);
        }
        return $html;
    }

    public function saveXML(DOMNode $node = null, $options = null)
    {
        if (is_null($node)) {
            return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . PHP_EOL . $this->saveHTML();
        }
        return parent::saveXML($node);
    }

}

अब के DOMEditorबजाय का उपयोग कर im DOMDocumentऔर यह मेरे लिए अब तक अच्छा काम किया है

        $editor = new DOMEditor();
        $editor->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        // works like a charm!
        echo $editor->saveHTML();

आपकी बात 1. mb_convert_encoding ($ string, 'HTML-ENTITIES', 'UTF-8') का उपयोग करके हल की गई है; loadHTML () और 2.nd का उपयोग करने से पहले अपने सहायक फ़ंक्शन में एक DIV टैग के आसपास mb_convert_encoding () आप उदाहरण के लिए उपयोग करते हैं। मेरे लिए काफी अच्छा रहा। वास्तव में यदि कोई DIV मौजूद नहीं है, तो यह स्वचालित रूप से मेरे मामले में एक पैराग्राफ जोड़ता है जो असुविधाजनक है क्योंकि आमतौर पर उनके पास कुछ मार्जिन (बूटस्ट्रैप ..) लागू होता है
ट्रैविनासिस

0

मैं इस मुद्दे पर भी आया था।

दुर्भाग्य से, मैंने इस धागे में दिए गए किसी भी समाधान का उपयोग करके आराम से महसूस नहीं किया, इसलिए मैं एक को जांचने के लिए गया जो मुझे संतुष्ट करेगा।

यहाँ मैंने क्या बनाया है और यह मुद्दों के बिना काम करता है:

$domxpath = new \DOMXPath($domDocument);

/** @var \DOMNodeList $subset */
$subset = $domxpath->query('descendant-or-self::body/*');

$html = '';
foreach ($subset as $domElement) {
    /** @var $domElement \DOMElement */
    $html .= $domDocument->saveHTML($domElement);
}

सार में यह यहाँ प्रदान किए गए अधिकांश समाधानों के समान तरीके से काम करता है, लेकिन मैन्युअल श्रम करने के बजाय यह शरीर के भीतर सभी तत्वों का चयन करने के लिए xpath चयनकर्ता का उपयोग करता है और उनके HTML कोड को सम्मिलित करता है।


यहां सभी समाधानों की तरह, यह हर मामले के लिए काम नहीं करता है: यदि लोड की गई स्ट्रिंग मार्कअप के साथ शुरू नहीं हुई थी, <p> </ p> जोड़ा गया है, तो आपका कोड काम नहीं करता है, क्योंकि यह जोड़ देगा। <p> </ p> में सहेजी गई सामग्री मार्कअप
copndz

निष्पक्ष होने के लिए, मैंने इसे कच्चे पाठ के साथ परीक्षण नहीं किया है, लेकिन सिद्धांत रूप में काम करना चाहिए। अपने विशिष्ट मामले के लिए आपको xpath को कुछ इस तरह बदलना पड़ सकता है descendant-or-self::body/p/*
निकोला पेटकंस्की

0

मेरे सर्वर को php 5.3 मिला और उन विकल्पों को अपग्रेड नहीं कर सकता

LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD

मेरे लिए नहीं हैं।

इसे हल करने के लिए मैं SaveXML फ़ंक्शन को बॉडी एलिमेंट को प्रिंट करने के लिए कहता हूं और फिर "बॉडी" को "डिव" से बदल देता हूं

यहाँ मेरा कोड है, आशा है कि यह किसी की मदद कर रहा है:

<? 
$html = "your html here";
$tabContentDomDoc = new DOMDocument();
$tabContentDomDoc->loadHTML('<?xml encoding="UTF-8">'.$html);
$tabContentDomDoc->encoding = 'UTF-8';
$tabContentDomDocBody = $tabContentDomDoc->getElementsByTagName('body')->item(0);
if(is_object($tabContentDomDocBody)){
    echo (str_replace("body","div",$tabContentDomDoc->saveXML($tabContentDomDocBody)));
}
?>

utf-8 हिब्रू समर्थन के लिए है।


0

एलेक्स का उत्तर सही है, लेकिन खाली नोड्स पर निम्नलिखित त्रुटि हो सकती है:

DOMNode को दिया गया तर्क 1 :: removeChild () DOMNode का एक उदाहरण होना चाहिए

यहाँ मेरा छोटा मॉड आता है:

    $output = '';
    $doc = new DOMDocument();
    $doc->loadHTML($htmlString); //feed with html here

    if (isset($doc->firstChild)) {

        /* remove doctype */

        $doc->removeChild($doc->firstChild);

        /* remove html and body */

        if (isset($doc->firstChild->firstChild->firstChild)) {
            $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
            $output = trim($doc->saveHTML());
        }
    }
    return $output;

व्हाट्सएप को हटाने के लिए ट्रिम () जोड़ना भी एक अच्छा विचार है।


0

मुझे शायद बहुत देर हो गई। लेकिन शायद किसी को (मेरे जैसे) अभी भी यह मुद्दा है।
इसलिए, उपरोक्त में से किसी ने भी मेरे लिए काम नहीं किया। क्योंकि $ dom-> loadHTML भी खुले टैगों को बंद कर देता है, न केवल html और बॉडी टैग्स जोड़ते हैं।
इसलिए एक <div> तत्व जोड़ें जो मेरे लिए काम नहीं कर रहा है, क्योंकि मुझे कभी-कभी html टुकड़े में 3-4 अछूता div पसंद है।
मेरा समाधान:

1.) काटने के लिए मार्कर जोड़ें, फिर html टुकड़ा लोड करें

$html_piece = "[MARK]".$html_piece."[/MARK]";
$dom->loadHTML($html_piece);

2.) जो कुछ भी आप दस्तावेज़ के साथ चाहते हैं
3.) html को सहेजें

$new_html_piece = $dom->saveHTML();

4.) इससे पहले कि आप इसे लौटाएं, मार्कर से <p> </ p> टैग हटा दें, अजीब तरह से यह केवल [MARK] पर दिखाई देता है, लेकिन [/ MARK] पर नहीं ...! ...

$new_html_piece = preg_replace( "/<p[^>]*?>(\[MARK\]|\s)*?<\/p>/", "[MARK]" , $new_html_piece );

5.) मार्कर से पहले और बाद में सब कुछ हटा दें

$pattern_contents = '{\[MARK\](.*?)\[\/MARK\]}is';
if (preg_match($pattern_contents, $new_html_piece, $matches)) {
    $new_html_piece = $matches[1];
}

6.) इसे वापस करो

return $new_html_piece;

अगर LIBXML_HTML_NOIMPLIED ने मेरे लिए काम किया तो यह बहुत आसान होगा। यह schould, लेकिन यह नहीं है। PHP 5.4.17, libxml संस्करण 2.7.8।
मुझे वास्तव में अजीब लगता है, मैं HTML डोम पार्सर का उपयोग करता हूं और फिर, इस "बात" को ठीक करने के लिए मुझे रेगेक्स का उपयोग करना होगा ... पूरे बिंदु था, रेगेक्स का उपयोग नहीं करना;)


खतरनाक लगता है कि आप यहां क्या करते हैं, stackoverflow.com/a/29499718/367456 को आपके लिए काम करना चाहिए।
हकरे

दुर्भाग्य से यह ( stackoverflow.com/questions/4879946/… ) मेरे लिए काम नहीं करेगा। जैसा कि मैंने कहा था: "तो मेरे लिए एक <div> तत्व जोड़ें काम नहीं कर रहा है, क्योंकि मुझे कभी-कभी html टुकड़े में 3-4 बिना नाप के div पसंद है" किसी कारण से, DOMDocument सभी "बंद नहीं" तत्वों को बंद करना चाहते हैं। मामले में, मैं एक शोर्ट या अन्य मार्कर के भीतर एक फ्रिक्शन प्राप्त करूंगा, फ़्रीलेशन को हटा दूंगा और मैं दस्तावेज़ के दूसरे टुकड़े में हेरफेर करना चाहता हूं, जब मैं उसके साथ करूंगा, तो मैं फ्रिक्शन वापस सम्मिलित करूंगा।
जो

इसके बजाय अपनी खुद की सामग्री को लोड करने के बाद शरीर तत्व को बाहर छोड़ना और शरीर तत्व पर काम करना संभव होना चाहिए। जब आप एक टुकड़ा लोड करते हैं तो शरीर के तत्व को स्पष्ट रूप से जोड़ा जाना चाहिए।
हैकर

मेरी समस्या यह है, मेरे फ्रीगेट में कोई टैग नहीं है। इसे अछूता नहीं रहना चाहिए और DOMDocument उन तत्वों को बंद कर देगा। जैसे Fregment: < div >< div > ... < /div >। मैं अभी भी समाधान की तलाश कर रहा हूं।
जो

हम्म, मुझे लगता है कि div टैग में हमेशा एक समापन जोड़ी होती है। शायद साफ सुथरा संभाल सकता है, यह टुकड़े के साथ भी काम कर सकता है।
हकरे

0

Drupal का उपयोग करने वाले किसी व्यक्ति के लिए, ऐसा करने के लिए फ़ंक्शन में बनाया गया है:

https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x

संदर्भ के लिए कोड:

function filter_dom_serialize($dom_document) {
  $body_node = $dom_document->getElementsByTagName('body')->item(0);
  $body_content = '';

  if ($body_node !== NULL) {
    foreach ($body_node->getElementsByTagName('script') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node);
    }

    foreach ($body_node->getElementsByTagName('style') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node, '/*', '*/');
    }

    foreach ($body_node->childNodes as $child_node) {
      $body_content .= $dom_document->saveXML($child_node);
    }
    return preg_replace('|<([^> ]*)/>|i', '<$1 />', $body_content);
  }
  else {
    return $body_content;
  }
}

Upvoted। Drupal API का यह फ़ंक्शन मेरे Drupal 7 साइट पर ठीक काम करता है। मुझे लगता है कि जो लोग Drupal का उपयोग नहीं कर रहे हैं वे फ़ंक्शन को अपनी साइट में कॉपी कर सकते हैं - क्योंकि इस बारे में Drupal-specific कुछ भी नहीं है।
नि: शुल्क कट्टरपंथी

0

आप केवल शो-बॉडी के साथ सुव्यवस्थित उपयोग कर सकते हैं:

$tidy = new tidy();
$htmlBody = $tidy->repairString($html, [
  'indent' =>  true,
  'output-xhtml' => true,
  'show-body-only' => true
], 'utf8');

लेकिन, रीमाइबर: कुछ टैग्स को हटा दें जैसे कि फ़ॉन्ट विस्मयकारी चिह्न: समस्याएँ HTML के साथ इंडेंट करना (5)


-1
#remove doctype tag
$doc->removeChild($doc->doctype); 

#remove html & body tags
$html = $doc->getElementsByTagName('html')[0];
$body = $html->getElementsByTagName('body')[0];
foreach($body->childNodes as $child) {
    $doc->appendChild($child);
}
$doc->removeChild($html);

साझा करने की देखभाल क्यों -1?
डायलन मैक्स

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.