এইচটিএমএল মোড়ক ছাড়াই ডিওএমডকুমেন্টের এইচটিএমএল কীভাবে সংরক্ষণ করবেন?


116

আমি নীচের ফাংশন, আমি ডোমডোকামেন্টটি এক্সএমএল, এইচটিএমএল, বডি এবং পি ট্যাগ র‍্যাপারগুলিকে সংযুক্ত না করে আউটপুট দেওয়ার জন্য লড়াই করছি content প্রস্তাবিত ফিক্স:

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

কেবল তখনই কাজ করে যখন সামগ্রীটির অভ্যন্তরে কোনও ব্লক স্তর উপাদান নেই। যাইহোক, এটি যখন h1 উপাদানটির সাথে নীচের উদাহরণ হিসাবে রয়েছে তখন সেভএক্সএমএল থেকে ফলাফল আউটপুট কেটে যাবে ...

<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

এই সমস্ত উত্তর এখনই ভুল , কারণ পিএইচপি 5.4 এবং লিবিএক্সএমএল ২.6- loadHTMLএর একটি $optionপ্যারামিটার রয়েছে যা লিবেক্সএমএলকে কীভাবে বিষয়বস্তুটিকে পার্স করতে হবে সে সম্পর্কে নির্দেশ দেয়।

অতএব, আমরা এই বিকল্পগুলির সাথে যদি HTML লোড করি

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

যখন করছেন saveHTML()কোন হতে হবে doctype, কোন <html>, এবং কোন <body>

LIBXML_HTML_NOIMPLIEDইমপ্লাইড এইচটিএমএল / বডি উপাদানগুলির স্বয়ংক্রিয় সংযোজনটি বন্ধ করে LIBXML_HTML_NODEFDTDদেয় যখন একটি খুঁজে পাওয়া যায় না তখন একটি ডিফল্ট ডক্টটাইপ যুক্ত হওয়া রোধ করে।

LibxML পরামিতি সম্পর্কে সম্পূর্ণ ডকুমেন্টেশন এখানে

(নোট loadHTMLনোটগুলি বলে যে LibxML 2.6 প্রয়োজন, তবে LIBXML_HTML_NODEFDTDএটি কেবল LibxML 2.7.8 LIBXML_HTML_NOIMPLIEDএ উপলব্ধ এবং LibxML 2.7.7 এ উপলব্ধ)


10
এটি একটি কবজির মতো কাজ করে। গ্রহণযোগ্য উত্তর হওয়া উচিত। আমি কেবল একটি পতাকা যুক্ত করেছি এবং আমার সমস্ত মাথাব্যাথা চলে গেছে ;-)
জাস্ট প্লেইন হাই

8
এটি পিএইচপি 5.4 এবং LibxML 2.9 এর সাথে কাজ করে না। লোডএইচটিএমএল কোনও বিকল্প গ্রহণ করে না :(
আকায়রা

11
মনে রাখবেন যে এটি বেশ নিখুঁত নয়। স্ট্যাকওভারফ্লো
জোশ লেভিনসন

4
দুঃখিত, তবে এটি মোটেও ভাল সমাধান বলে মনে হচ্ছে না (কমপক্ষে অনুশীলনে নয়)। এটি সত্যিকারের গ্রহণযোগ্য উত্তর হওয়া উচিত নয়। উল্লিখিত সমস্যাগুলি ছাড়াও, এর সাথে একটি বাজে এনকোডিং সমস্যা রয়েছে DOMDocumentযা এই উত্তরের কোডকেও প্রভাবিত করে। আফাইক, DOMDocumentইনপুটটি সর্বদা ল্যাটিন -১ হিসাবে ব্যাখ্যা করে যদি না ইনপুটটি আলাদা অক্ষরে বর্ণিত হয় । অন্য কথায়: <meta charset="…">ট্যাগটি ইনপুট ডেটার জন্য প্রয়োজনীয় বলে মনে হচ্ছে যা লাতিন -১ নয়। অন্যথায় আউটপুট যেমন ইউটিএফ -8 মাল্টিবাইট অক্ষরের জন্য ভেঙে যাবে।
মার্শহাউস

1
LIBXML_HTML_NOIMPLIED ট্যাবগুলি, ইন্ডেন্টগুলি এবং লাইন ব্রেকগুলি সরিয়ে HTML কোড
মেসেজ করে

72

লোড এইচটিএমএল () সহ নথিটি লোড করার পরে সরাসরি নোডগুলি সরান:

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

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

এটি আমার কাছে পরিষ্কার উত্তর।
KnF

39
উল্লেখ্য হওয়া উচিত যে <body> এর একটিমাত্র সন্তানের নোড থাকলে এটি কাজ করে।
ইয়ান মিলিন

দুর্দান্ত কাজ করেছেন ধন্যবাদ! অন্যান্য প্রাক উত্তরগুলির চেয়ে অনেক বেশি ক্লিনার এবং দ্রুত।
লিগামার

এই জন্য আপনাকে ধন্যবাদ! খালি নোডগুলি হ্যান্ডেল করতে আমি নীচে আরও একটি স্নিপ যুক্ত করেছি।
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 () এইচটিএমএল নয়, এক্সএইচটিএমএল সংরক্ষণ করবে।
অ্যালেক্সান্ট

@ স্কট: এটি সত্যিই অদ্ভুত। উদাহরণস্বরূপ বিভাগে আপনি ঠিক কী করতে চেষ্টা করছেন তা এটি দেখায়। আপনি কি নিশ্চিত যে আপনার ডিওমে এইচটিএমএল নেই? আপনার ডমডকুমেন্টে ঠিক কী এইচটিএমএল রয়েছে? এটি হতে পারে যে আমাদের একটি শিশু নোড অ্যাক্সেস করতে হবে।
জোনাহ

@ জোনাঃ এটি আশ্চর্যের নয়। আপনি যখন loadHTMLlibxML করেন তখন HTML পার্সার মডিউল ব্যবহার করে এবং এটি অনুপস্থিত এইচটিএমএল কঙ্কালটি সন্নিবেশ করবে। ফলস্বরূপ, $dom->documentElementমূল HTML উপাদান হবে। আমি আপনার উদাহরণ কোড স্থির করেছি। স্কট যা বলছে তা এখন করা উচিত।
গর্ডন 21

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। প্রথমত, substrএটি HTML / BODY ট্যাগগুলি সরানো সহজ করে removal দ্বিতীয়ত, আমরা ডকটাইপটি সরিয়ে নেই substrকারণ আমরা জানি না যে ' default doctype' সর্বদা একটি নির্দিষ্ট দৈর্ঘ্যের কিছু হবে। তবে, সর্বাপেক্ষা গুরুত্বপূর্ণ, LIBXML_HTML_NODEFDTDডম পার্সারটিকে নথিতে নন-এইচটিএমএল 5 ডক্টিপ প্রয়োগ করা থেকে বিরত রাখে - যা অন্তত পার্সারকে এমন উপাদানগুলির চিকিত্সা থেকে বিরত রাখে যা এটি আলগা পাঠ্য হিসাবে স্বীকৃতি দেয় না।

আমরা এই সত্যের জন্য জানি যে এইচটিএমএল / বডি ট্যাগগুলি নির্দিষ্ট দৈর্ঘ্য এবং অবস্থানের হয় এবং আমরা জানি যে ধরণের ধ্রুবকগুলি LIBXML_HTML_NODEFDTDকোনও প্রকার অবমূল্যায়নের বিজ্ঞপ্তি ছাড়াই কখনই সরানো হয় না, সুতরাং উপরের পদ্ধতিটি ভবিষ্যতে ভালভাবে ঘুরতে হবে, তবে ...


... কেবলমাত্র সাবধানতাটি হ'ল ডম বাস্তবায়ন HTML / BODY ট্যাগগুলিতে নথির মধ্যে রাখার উপায় পরিবর্তন করতে পারে - উদাহরণস্বরূপ, নথির শেষে নিউলাইনটি সরিয়ে, ট্যাগগুলির মধ্যে ফাঁকা স্থান যোগ করা বা নতুনলাইন যুক্ত করা।

এটি খোলার জন্য এবং ট্যাগগুলি বন্ধ করার অবস্থানগুলির অবস্থান অনুসন্ধান 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 -> 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
এটি যদিও অবৈধ এইচটিএমএল এর জন্য ব্যর্থ হবে।
গর্ডন 21

1
@ গর্ডন ঠিক কীভাবে আমি অস্বীকারকে নীচে রেখেছি!
নিঃসঙ্গ দিন 21

1
আমি যখন এটি চেষ্টা করে দেখি এবং cho dom-> সেভ এইচটিএমএল () প্রতিধ্বনিত করি তখন এটি খালি স্ট্রিংটি দেয়। যেন লোডএক্সএমএল ($ সামগ্রী) খালি রয়েছে। আমি যখন $ dom-> লোডএইচটিএমএল ($ বিষয়বস্তু) দিয়ে একই কাজ করি, তারপরে প্রতিধ্বনি অনুযায়ী $ dom-> saveXML () প্রতিচ্ছবিটি পাই।
স্কট বি

এইচটিএমএল লোড করতে ইচ্ছুক হলে লোডএক্সএমএল ব্যবহার করা থাম্ব। বিশেষত কারণ লোডএক্সএমএল এইচটিএমএল হ্যান্ডেল করতে জানেন না।
বোটেনউউভার

15

ডোমডোকামেন্টফ্রেগমেন্ট ব্যবহার করুন

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

3
প্রাক php5.4 এর জন্য সবচেয়ে পরিষ্কার উত্তর।
নিক জনসন

এটি আমার জন্য লিঙ্কএক্সএমএল ২.7..7 সংস্করণের চেয়ে পুরানো এবং নতুন উভয় ক্ষেত্রেই কাজ করে। এটি সম্পূর্ণরূপে পিএইচপি 5.4 এর জন্য কেন হবে?
রবার্টটি

এর বেশি ভোট হওয়া উচিত। LIBXML_HTML_NOIMPLIED | সমর্থন করে না এমন libxML সংস্করণের জন্য দুর্দান্ত বিকল্প LIBXML_HTML_NODEFDTD। ধন্যবাদ!
মার্টি মুলিগান

13

এটি 2017, এবং এই 2011 প্রশ্নের জন্য আমি উত্তরগুলির কোনও পছন্দ করি না। প্রচুর রেগেক্স, বড় ক্লাস, লোডএক্সএমএল ইত্যাদি ...

সহজ সমাধান যা জানা সমস্যাগুলি সমাধান করে:

$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 = '<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। বিটিডব্লিউ, আপনার এখানে সর্বাধিক মার্জিত সমাধান। সম্মত।
এইচএলএসজি

10

আমি ক্লাবটিতে কিছুটা দেরি করেছি তবে আমি যে পদ্ধতিটি জানতে পেরেছি তা ভাগ করে নিতে চাইনি। সবার আগে আমি এই দুর্দান্ত বিকল্পগুলি গ্রহণ করার জন্য লোডএইচটিএমএল () এর জন্য সঠিক সংস্করণ পেয়েছি, তবে LIBXML_HTML_NOIMPLIEDআমার সিস্টেমে কাজ করে নি। এছাড়াও ব্যবহারকারীগণ পার্সার নিয়ে সমস্যাগুলি রিপোর্ট করে (উদাহরণস্বরূপ এখানে এবং এখানে )।

সমাধানটি আমি আসলে তৈরি করেছি খুব সহজ।

এইচটিএমএল লোড করা হবে একটি এ <div> তাই এটিতে উপাদান যুক্ত যাতে এতে লোড হওয়ার জন্য সমস্ত নোড যুক্ত একটি ধারক রয়েছে।

তারপরে এই ধারক উপাদানটি দস্তাবেজ থেকে সরানো হয়েছে (তবে এটির ডোমলেটটি এখনও বিদ্যমান)।

তারপরে ডকুমেন্ট থেকে সমস্ত সরাসরি বাচ্চাদের সরিয়ে ফেলা হবে। এর মধ্যে কোনও যুক্ত <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 = new DOMXPath($doc);
foreach ($xpath->query('/p') as $element)
{   #                   ^- note the single slash "/"
    # ... each of the two <p> element

  • পিএইচপি 5.4.36-1 + deb.sury.org ~ সুনির্দিষ্ট + 2 (ক্লিপ) (নির্মিত: 21 ডিসেম্বর 2014 20:28:53)

এটি আরও জটিল এইচটিএমএল উত্স নিয়ে আমার পক্ষে কাজ করে নি। এটি এইচটিএমএলের প্রদত্ত অংশটিকেও সরিয়ে দিয়েছে।
জোল্টন সলে

4

এই লেখার সময় অন্য কোনও সমাধান (জুন, ২০১২) আমার চাহিদা সম্পূর্ণরূপে মেটাতে সক্ষম হয় নি, তাই আমি নিম্নলিখিত বিষয়গুলি পরিচালনা করে এমন একটি লিখেছিলাম:

  • প্লেইন-পাঠ্য সামগ্রী গ্রহণ করে যার কোনও ট্যাগ নেই, পাশাপাশি এইচটিএমএল সামগ্রী রয়েছে।
  • কোনো ট্যাগ যোগ করবেন না (তত্সহ <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
এইচটিএমএল = / = এক্সএমএল, আপনার এইচটিএমএলের জন্য এইচটিএমএল লোডার ব্যবহার করা উচিত।
হাক্রে

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
}

ঠিক আছে, আশা করি এটি কিছু বাদ দেয় না এবং কাউকে সহায়তা করে?


2
লোড এইচটিএমএল কোনও মার্কআপ ব্যতীত কোনও স্ট্রিং লোড করার সময় কেসটি পরিচালনা করে না
কোপেন্ডজ

3

এই ফাংশনটি ব্যবহার করুন

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

13
এমন কিছু পাঠকই থাকতে পারেন যারা এই পোস্টের মাধ্যমে এই পোস্টটি জুড়ে হোঁচট খেয়েছেন, তাদের এইচটিএমএলকে বিশ্লেষণ করতে এবং তার পরিবর্তে একটি ডিওএম পার্সার ব্যবহার করার জন্য রেজেক্স না ব্যবহার করার সিদ্ধান্ত নিয়েছেন, এবং সম্পূর্ণ সমাধান অর্জনের জন্য সম্ভবত একটি রেজেক্স উত্তর প্রয়োজন ... হাস্যকর
রবি অ্যাভারিল

আমি বুঝতে পারি না কেন নোবাই কেবলমাত্র BODY এর সামগ্রীতে ফিরে আসে। পার্সার যখন পুরো ডকুমেন্ট শিরোনাম / ডক্টাইপ যুক্ত করে থাকে তখন কি সেই ট্যাগটি সর্বদা উপস্থিত থাকার জন্য অনুমিত হয় না? উপরের রেজেক্স এমনকি ছোট হবে।
সার্জিও

@ বাক্সিওর "এটি কাজ করে" - তবে আমরা কেন প্রথম স্থানে ডোম পার্সার পদ্ধতি ব্যবহার করছি?
আপনাকে ধন্যবাদ

@ নোমিক আমি ডিওএম পার্সার ব্যবহার না করার কথা বলিনি, একই ফল অর্জনের জন্য অবশ্যই অনেকগুলি ভিন্ন উপায় রয়েছে, এটি আপনার পক্ষে, আমি এই ফাংশনটি ব্যবহার করার সময় বিল্ট-ইন পিএইচপি ডোম নিয়ে আমার সমস্যা ছিল পার্সার, যা এইচটিএমএল 5 সঠিকভাবে পার্স করছে না।
Boksiora

1
আমাকে ব্যবহার করতে হয়েছিল preg_replaceকারণ এইচটিএমএল এবং বডি ট্যাগগুলি মুছে ফেলার জন্য ডোমডোকামেন্ট-ভিত্তিক পদ্ধতিগুলি ইউটিএফ -8 এনকোডিং সংরক্ষণ করছে না :(
উইজোনসোলিউশন

3

যদি আলেসান্দ্রো ভেন্ড্রুস্কো উত্তর দেওয়া ফ্ল্যাগগুলির সমাধান কাজ না করে তবে আপনি এটি চেষ্টা করতে পারেন:

$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<body>ট্যাগটি বাদে এই সমস্ত এইচটিএমএল মোড়ক ছাড়াই আপনার সম্পূর্ণ প্রক্রিয়াজাত এইচটিএমএল কোডটি থাকবে , যা আপনার সামগ্রীর মূল the তারপরে আপনি এটিকে চূড়ান্ত স্ট্রিং (পরে saveHTML) থেকে অপসারণ করতে একটি রেজেক্স বা একটি ট্রিম ফাংশন ব্যবহার করতে পারেন বা উপরের কেসের মতো, তার সমস্ত সন্তানের উপর পুনরাবৃত্তি করতে পারেন, তাদের সামগ্রীগুলি একটি অস্থায়ী পরিবর্তনশীলে সংরক্ষণ করে $finalHtmlএটি ফিরিয়ে দিতে (আমি কী বিশ্বাস করি নিরাপদ)।


3

আমি পিএইচপি 5.6.25 এবং লিবিএক্সএমএল ২.৯ চলমান আরএইচইএল 7 এ নিয়ে লড়াই করছি। (2018 এর পুরানো জিনিসগুলি, আমি জানি, তবে এটি আপনার জন্য রেড হ্যাট)

আমি দেখতে পেয়েছি যে আলেসান্দ্রো ভেন্ড্রুস্কোলো দ্বারা প্রস্তাবিত অনেক আপভোটেড সমাধানটি ট্যাগগুলি পুনরায় সাজানোর মাধ্যমে এইচটিএমএলকে ভেঙে দেয়। অর্থাৎ,

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

হয়ে:

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

এটি আপনার ব্যবহারের পরামর্শ দেয়: LIBXML_HTML_NOIMPLIEDএবং LIBXML_HTML_NODEFDTD

অ্যালেক্সের প্রস্তাবিত সমাধানটি সমাধানের অর্ধেক পথ যায়, তবে <body>একাধিক সন্তানের নোড থাকলে এটি কাজ করে না ।

আমার জন্য যে সমাধানটি কাজ করে তা হ'ল ফলউইং:

প্রথমে, ডোমডোকামেন্টটি লোড করতে, আমি ব্যবহার করি:

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

DOMDocament ম্যাসেজ করার পরে দস্তাবেজটি সংরক্ষণ করতে, আমি ব্যবহার করি:

// 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>

বার্টকে ধন্যবাদ


2

আমারও এই প্রয়োজনীয়তা ছিল এবং উপরে আলেক্স পোস্ট করা সমাধানটি পছন্দ করেছিলাম। যদিও বেশ কয়েকটি সমস্যা <body>রয়েছে - যদি উপাদানটিতে একাধিক শিশু উপাদান থাকে তবে ফলস্বরূপ নথিতে কেবলমাত্র প্রথম সন্তানের উপাদান থাকবে <body>, সবগুলিই নয়। এছাড়াও, শর্তসাপেক্ষে জিনিসগুলি হ্যান্ডেল করার জন্য আমার স্ট্রিপিংয়ের দরকার ছিল - কেবলমাত্র যখন আপনি এইচটিএমএল শিরোনামের সাথে নথি রেখেছিলেন। সুতরাং আমি নীচে এটি পরিমার্জন। অপসারণের পরিবর্তে <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

অন্যান্য সদস্যদের মতো অনেকটা, আমি প্রথম @ আলেসান্দ্রো ভেন্ড্রুস্কো উত্তরের সরলতা এবং অসাধারণ শক্তিতে উদ্ভাসিত হয়েছি। কিছু পতাকাঙ্কিত ধ্রুবকগুলিতে কেবল কনস্ট্রাক্টরের কাছে যাওয়ার ক্ষমতাটি সত্য বলে মনে হয় খুব ভাল। আমার জন্য ছিল। আমার কাছে উভয়ই লিবিএক্সএমএল এবং পিএইচপি-র সঠিক সংস্করণ রয়েছে তবে এটি ডকুমেন্ট অবজেক্টের নোড কাঠামোতে এটি এইচটিএমএল ট্যাগ যুক্ত করবে তা নির্বিশেষে।

আমার সমাধানটি ব্যবহার করার চেয়ে ভালভাবে কাজ করেছে ...

$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);

নোড অপসারণ, যা ডিওমে কোনও কাঠামোগত আদেশ ছাড়াই অগোছালো হয়ে যায়। আবার কোড টুকরাগুলির ডিওএম কাঠামো পূর্বনির্ধারনের কোনও উপায় নেই।

আমি এই যাত্রাটি ডিওএম ট্র্যাভারসাল করার সহজ উপায়ের সন্ধানে এই যাত্রাটি শুরু করেছিলাম কীভাবে জিকুয়ারি এটি করেন বা কমপক্ষে এমন কোনও ফ্যাশনে কাঠামোগত ডেটা সেট করেছিলেন যা এককভাবে সংযুক্ত, দ্বিগুণভাবে লিঙ্কযুক্ত বা ট্রি নোড ট্র্যাভারসাল। আমি যতক্ষণ না এইচটিএমএল যেভাবে স্ট্রিংকে পার্স করতে পারি এবং সেই পথে নোড সত্তা শ্রেণীর বৈশিষ্ট্যগুলির আশ্চর্যজনক শক্তি থাকতে পারে সেদিকে আমি খেয়াল করিনি।

এখনও অবধি ডমডকুমেন্ট অবজেক্টটি আমাকে চাওয়া ছেড়ে দিয়েছে ... অন্যান্য প্রোগ্রামারদের মতো এটি মনে হচ্ছে ... আমি জানি আমি শেষ পর্যন্ত এই প্রশ্নটিতে অনেক হতাশাকে দেখেছি .... (প্রায় 30 ঘন্টা চেষ্টা করে ব্যর্থ হওয়ার পরে) টাইপ টেস্টিং) এগুলি সব করার একটি উপায় খুঁজে পেয়েছি। আমি আশা করি এটা কারো সাহায্যে লাগবে...

প্রথমে, আমি সমস্ত কিছুর প্রতি কৌতুকময় ... লোল ...

এই ব্যবহারের ক্ষেত্রে তৃতীয় পক্ষের শ্রেণি যেভাবেই প্রয়োজন সে বিষয়ে কারও সাথে একমত হওয়ার আগে আমি আজীবন যেতে পারতাম। আমি খুব তৃতীয় পক্ষের কোনও শ্রেণিবদ্ধ কাঠামো ব্যবহার করার অনুরাগী নই এবং আমি দুর্দান্ত পার্সারে গিয়ে হোঁচট খেয়েছি। (গুগল দেওয়ার আগে প্রায় 30 বার গুগল তাই দেয়ার আগে একা বোধ করবেন না কারণ এটি কোনওভাবেই সরল অবস্থায় পড়েছে বলে মনে হচ্ছে ...)

যদি আপনি কোডের টুকরোগুলি ব্যবহার করে থাকেন এবং কোনও অতিরিক্ত ট্যাগ ব্যবহার না করে কোনওভাবে পার্সার দ্বারা কোড পরিষ্কার এবং অকারণে প্রয়োজন হয় তবে সিম্পিএইচপিপি পার্সার ব্যবহার করুন

এটি আশ্চর্যজনক এবং JQuery এর মতো অনেকগুলি কাজ করে। আমি প্রায়শই মুগ্ধ হই না তবে এই শ্রেণিটি প্রচুর ভাল সরঞ্জাম ব্যবহার করে এবং এখনও পর্যন্ত আমার কোনও পার্সিং ত্রুটি নেই। এই ক্লাসটি যা করতে পারে তা করতে পেরে আমি একজন বিশাল ভক্ত।

ডাউনলোড করার জন্য এর ফাইলগুলি খুঁজে পেতে পারেন এখানে , তার প্রারম্ভে নির্দেশাবলী এখানে , এবং তার এপিআই এখানে । আমি এই ক্লাসটিকে তার সহজ পদ্ধতিগুলির সাথে ব্যবহারের সুপারিশ করছি যা .find(".className")কোনও জিকুয়েরি আবিষ্কারের পদ্ধতিটি ব্যবহার করতে পারে এমনভাবে বা এমনকি পরিচিত পদ্ধতি যেমন getElementByTagName()বা getElementById()...

আপনি যখন এই শ্রেণীর কোনও নোড গাছ সংরক্ষণ করেন তখন এটি কোনও কিছুই যুক্ত করে না। আপনি কেবল বলতে পারেন $doc->save();এবং এটি কোনও গাছপালা ছাড়াই পুরো গাছটিকে একটি স্ট্রিংয়ে আউটপুট করে।

ভবিষ্যতে এখন আমি এই পার্সারটি সমস্ত, ক্যাপড-ব্যান্ডউইথ, প্রকল্পগুলির জন্য ব্যবহার করব।


2

আমার পিএইচপি 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এই যখন একাধিক এইচটিএমএল / XML দস্তাবেজগুলিতে সাধিত কোড "বিবেকী" রাখা গুরুত্বপূর্ণ হতে পারে


এটি খণ্ডগুলির জন্য কাজ করবে না, কেবলমাত্র সেই একক শিশু-উপাদানটির জন্য যা আপনি নথির প্রথম-শিশু করতে চান। এটি বেশ সীমিত এবং কার্যকরভাবে এটি কাজ করে না LIBXML_HTML_NOIMPLIEDযেমন এটি কেবল আংশিকভাবে করে। DOCTYPE ও মুছে ফেলার পদ্ধতি কার্যকরভাবে হয় LIBXML_HTML_NODEFDTD
hakre

2

এইচটিএমএল মোড়ক মুছে ফেলার উপায় খুঁজতে আমি এই বিষয়টি জুড়ে এসেছি। ব্যবহার 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 এর সমস্যার জন্য দেওয়া উত্তরটি অস্পষ্ট। আমি আপনার ভাল উদ্দেশ্যকে সম্মান করি, তবে দয়া করে সচেতন হন যে এটি প্রচুর শোরগোল তৈরি করতে পারে এবং অন্যেরা তাদের সমাধানের সন্ধান করতে বাধা সৃষ্টি করতে পারে যা আমি অনুমান করি যে আপনি নিজের উত্তর দিয়ে কী অর্জন করতে চান তার বিপরীত। আপনি যদি একবারে একটি করে প্রশ্ন পরিচালনা করেন তবে স্ট্যাকওভারফ্লো সবচেয়ে ভাল কাজ করে। শুধু একটি ইঙ্গিত।
hakre

2

আমি DOMDocumentক্লাসে 3 টি সমস্যায় পড়ি ।

1- এই শ্রেণিটি ISO এনকোডিং এবং এইচটিএমএল 8 টি অক্ষর আউটপুট না দেখিয়ে লোড করে html load

2- এমনকি আমরা দিই কি না ‍‍‍‍‍‍‍LIBXML_HTML_NOIMPLIED loadHtml পদ্ধতি

3- এই শ্রেণিটি এইচটিএমএল 5 ট্যাগকে অবৈধ মনে করে।

সুতরাং আমি এই সমস্যাগুলি সমাধান করতে এই বর্গটি ওভাররাইড করেছি এবং আমি কয়েকটি পদ্ধতি পরিবর্তন করেছি।

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পরিবর্তে ব্যবহার করছি DOMDocumentএবং এটি এখন পর্যন্ত আমার পক্ষে ভাল কাজ করেছে

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

আপনার পয়েন্ট 1.টি mb_convert_encoding ($ স্ট্রিং, 'HTML-ENTITIES', 'UTF-8') ব্যবহার করে সমাধান করা হয়েছে; লোডএইচটিএমএল () এবং ২. তম ব্যবহারের পূর্বে আপনার সহায়ক ফাংশনটিতে, এমবি_কন্ট্র্ট_কেনডিং () এর কাছাকাছি আপনি উদাহরণ হিসাবে ব্যবহার করেন around আমার জন্য যথেষ্ট ভাল কাজ করেছে। প্রকৃতপক্ষে যদি কোনও ডিআইভি উপস্থিত না থাকে তবে এটি স্বয়ংক্রিয়ভাবে আমার ক্ষেত্রে একটি অনুচ্ছেদ যুক্ত করে যা অসুবিধার কারণ সাধারণত তাদের কিছুটা মার্জিন প্রয়োগ হয় (বুটস্ট্র্যাপ ..)
ট্রেনোসিস ২is

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);
}

মূলত এটি এখানে প্রদত্ত বেশিরভাগ সমাধানগুলিতে একইভাবে কাজ করে, তবে ম্যানুয়াল শ্রমের পরিবর্তে এটি শরীরের মধ্যে থাকা সমস্ত উপাদান নির্বাচন করতে এবং তাদের এইচটিএমএল কোডকে সম্মতি জানাতে এক্সপাথ নির্বাচনকারী ব্যবহার করে।


এখানে সমস্ত সমাধানের মতো, এটি প্রতিটি ক্ষেত্রে কাজ করে না: যদি বোঝা স্ট্রিংটি মার্কআপ দিয়ে শুরু না হয়, <p> </p> যোগ করা হয়েছে, তবে আপনার কোডটি কাজ করে না, যেহেতু এটি যুক্ত করবে <p> </p> সংরক্ষিত সামগ্রীতে মার্কআপ
কোপেন্ডজ

সত্যি কথা বলতে, আমি এটি কাঁচা পাঠ্য দিয়ে পরীক্ষা করিনি, তবে তাত্ত্বিকভাবে কাজ করা উচিত। আপনার নির্দিষ্ট ক্ষেত্রে আপনার xpath এর মতো কিছুতে পরিবর্তন করতে হবে descendant-or-self::body/p/*
নিকোলা পেটকানস্কি

0

আমার সার্ভার পিএইচপি 5.3 পেয়েছে এবং তাই এই বিকল্পগুলি আপগ্রেড করতে পারে না

LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD

আমার জন্য না

এটি সমাধান করার জন্য আমি বডি এলিমেন্টটি মুদ্রণের জন্য সেভএক্সএমএল ফাংশনকে বলি এবং তারপরে "দেহ" কে "ডিভ" দিয়ে প্রতিস্থাপন করি

এখানে আমার কোড, আশা করি এটি কাউকে সাহায্য করবে:

<? 
$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

অ্যালেক্স উত্তরটি সঠিক, তবে খালি নোডগুলিতে নিম্নলিখিত ত্রুটির কারণ হতে পারে:

আর্গুমেন্ট 1 ডোমনোডে পাস হয়েছে :: সরানোচিল্ড () অবশ্যই ডিওএমএনডের একটি উদাহরণ হতে হবে

এখানে আমার সামান্য মোড আসে:

    $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

আমার হয়তো অনেক দেরি হয়ে গেছে। তবে সম্ভবত কারও (আমার মতো) এখনও এই সমস্যাটি রয়েছে।
সুতরাং, উপরের কেউই আমার পক্ষে কাজ করেননি। কারণ $ ডম-> লোডএইচটিএমএল পাশাপাশি খোলা ট্যাগগুলিও বন্ধ করে দেয়, কেবল এইচটিএমএল এবং বডি ট্যাগ যুক্ত করে না।
সুতরাং একটি <div> উপাদান যুক্ত করুন আমার পক্ষে কাজ করছে না, কারণ আমার মাঝে মাঝে এইচটিএমএল টুকরোতে 3-4 টি অনাবৃত ডিভের মতো থাকে।
আমার সমাধান:

1.) কাটাতে চিহ্নিতকারী যুক্ত করুন, তারপরে এইচটিএমএল টুকরো লোড করুন

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

২) ডকুমেন্টটি দিয়ে
যা খুশি করুন)) এইচটিএমএল সংরক্ষণ করুন

$new_html_piece = $dom->saveHTML();

৪.) আপনি এটি ফিরিয়ে দেওয়ার আগে <পি> </ p> ট্যাগগুলি চিহ্নিতকারী থেকে সরান, আশ্চর্যের বিষয় এটি কেবল [মার্ক] তে প্রদর্শিত হয় তবে [/ মার্ক] তে না ... !?

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

৫) চিহ্নিতকারীর আগে এবং পরে সমস্ত কিছু সরিয়ে ফেলুন

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

)) এটি ফিরিয়ে দিন

return $new_html_piece;

যদি LIBXML_HTML_NOIMPLIED আমার পক্ষে কাজ করে তবে এটি অনেক সহজ হবে। এটি schould, কিন্তু এটি না। পিএইচপি 5.4.17, libxML সংস্করণ 2.7.8।
আমি সত্যিই অদ্ভুত বলে মনে করি, আমি এইচটিএমএল ডিওএম পার্সার ব্যবহার করি এবং তারপরে, এই "জিনিসটি" ঠিক করার জন্য আমাকে রিজেক্স ব্যবহার করতে হবে ... পুরো কথাটি ছিল, রেজেক্স ব্যবহার করার জন্য নয়;)


আপনি এখানে যা করছেন তা বিপজ্জনক বলে মনে হচ্ছে, আপনার জন্য কাজটি স্ট্যাকওভারফ্লো.com / a / 29499718 / 367456 করা উচিত।
hakre

দুর্ভাগ্যক্রমে এটি ( স্ট্যাকওভারফ্লো / প্রশ্ন / 4879946/… ) আমার পক্ষে কাজ করবে না। যেমনটি আমি বলেছিলাম: "সুতরাং << বিভাজন যোগ করুন উপাদানটি আমার পক্ষে কাজ করছে না, কারণ আমার মাঝে মাঝে এইচটিএমএল টুকরাটিতে 3-4 টি অনাবৃত ডিভের মতো থাকে" কোনও কারণে, ডমডকুমেন্টটি সমস্ত "বন্ধ নয়" উপাদানগুলি বন্ধ করতে চায়। সেক্ষেত্রে, আমি একটি শর্টকোড বা অন্য চিহ্নিতকারীগুলির মধ্যে একটি ঝাঁকুনি পেয়ে যাব, ফ্রেগমেন্টটি সরিয়ে ফেলব এবং নথির অন্য অংশটি আমি হেরফের করতে চাই, যখন আমি এটি সম্পন্ন করেছি, তখন আমি ফ্রেগমেন্টটি sertোকিয়ে দেব।
জো

পরিবর্তে আপনার নিজস্ব সামগ্রী লোড করার পরে ডিভ উপাদানটি বাইরে রেখে দেহের উপাদানটিতে কাজ করা সম্ভব উচিত। আপনি যখন কোনও খণ্ড লোড করবেন তখন শরীরের উপাদানটি স্পষ্টভাবে যুক্ত করা উচিত।
হ্যাক্রে

আমার সমস্যাটি হ'ল, আমার ফ্রেগমেন্টের কন্টেন্টটি আনলসড ট্যাগ। এটি আবদ্ধ থাকা উচিত এবং ডোমডকুমেন্ট সেই উপাদানগুলিকে বন্ধ করে দেবে। মত Fregment: < div >< div > ... < /div >। আমি এখনও সমাধান খুঁজছি।
জো

হুম, আমি মনে করি ডিভ ট্যাগগুলিতে সর্বদা একটি বন্ধের জুটি থাকে। সম্ভবত পরিপাটি এটি পরিচালনা করতে পারে, এটি টুকরো টুকরো দিয়েও কাজ করতে পারে।
হ্যাক্রে

0

যে কেউ দ্রুপাল ব্যবহার করছেন, এটি করার জন্য কার্যত একটি বিল্ট ইন রয়েছে:

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;
  }
}

সম্মত। ড্রুপাল এপিআই থেকে এই ফাংশনটি আমার ড্রুপাল 7 সাইটে সূক্ষ্মভাবে কাজ করে Us আমার ধারণা, যারা ড্রুপাল ব্যবহার করছে না তারা কেবল ফাংশনটি তাদের নিজস্ব কপিরাইটে অনুলিপি করতে পারে - কারণ এ সম্পর্কে ড্রুপাল-নির্দিষ্ট কিছুই নেই।
ফ্রি র‌্যাডিকাল

0

আপনি কেবল শো-বডি-তে পরিপাটি ব্যবহার করতে পারেন:

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

তবে, রেমেডার: পরিপাটি ফন্ট আশ্চর্য আইকনগুলির মতো কিছু ট্যাগ সরিয়ে ফেলুন: পিএইচপি সহ HTML (5) ইনডেন্টিংয়ে সমস্যা



আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.