<p>I have a bunch of legacy documents that are HTML-like.  As in, they look like HTML, but have additional made up tags that aren't a part of HTML</p>

<pre><code>&lt;strong&gt;This is an example of a &lt;pseud-template&gt;fake tag&lt;/pseud-template&gt;&lt;/strong&gt;
</code></pre>

<p>I need to parse these files. PHP is the only only tool available. The documents don't come close to  being well formed XML.  </p>

<p>My original thought was to use the loadHTML methods on PHPs DOMDocument.  However, these methods choke on the make up HTML tags, and will refuse to parse the string/file.</p>

<pre><code>$oDom = new DomDocument();
$oDom-&gt;loadHTML("&lt;strong&gt;This is an example of a &lt;pseud-template&gt;fake tag&lt;/pseud-template&gt;&lt;/strong&gt;");
//gives us
DOMDocument::loadHTML() [function.loadHTML]: Tag pseud-template invalid in Entity, line: 1 occured in ....
</code></pre>

<p>The only solution I've been able to come up with is to pre-process the files with string replacement functions that will remove the invalid tags and replace them with a valid HTML tag (maybe a span with an id of the tag name).</p>

<p>Is there a more elegant solution?  A way to let DOMDocument know about additional tags to consider as valid?  Is there a different, robust HTML parsing class/object out there for PHP?</p>

<p>(if it's not obvious, I don't consider regular expressions a valid solution here)</p>

<p><strong>Update</strong>: The information in the fake tags is part of the goal here, so something like Tidy isn't an option.  Also, I'm after something that does the some level, if not all, of well-formedness cleanup for me, which is why I was looking the DomDocument's loadHTML method in the first place.</p>

[{'answer_id': 66811, 'author': 'Paul Dixon', 'author_id': 6521, 'author_profile': 'https://Stackoverflow.com/users/6521', 'pm_score': 2, 'selected': False, 'text': '<p>I wonder if passing the "bad" HTML through <a href="http://www.w3.org/People/Raggett/tidy/" rel="nofollow noreferrer">HTML Tidy</a> might help as a first pass? Might be worth a look, if you can get the document to be well formed, maybe you could load it as a regular XML file with DomDocument.</p>\n'}, {'answer_id': 67115, 'author': 'nickf', 'author_id': 9021, 'author_profile': 'https://Stackoverflow.com/users/9021', 'pm_score': 1, 'selected': False, 'text': '<p>@Twan\nYou don\'t need a DTD for DOMDocument to parse custom XML. Just use <code>DOMDocument-&gt;load()</code>, and as long as the XML is well-formed, it can read it.</p>\n\n<p>Once you get the files to be well-formed, that\'s when you can start looking at XML parsers, before that you\'re S.O.L. Lok Alejo said, you could look at <a href="http://www.w3.org/People/Raggett/tidy/" rel="nofollow noreferrer">HTML TIDY</a>, but it looks like that\'s specific to HTML, and I don\'t know how it would go with your custom elements.</p>\n\n<blockquote>\n  <p>I don\'t consider regular expressions a valid solution here</p>\n</blockquote>\n\n<p>Until you\'ve got well-formedness, that might be your only option. Once you get the documents to that stage, then you\'re in the clear with the DOM functions.</p>\n'}, {'answer_id': 67201, 'author': 'Ged Byrne', 'author_id': 10167, 'author_profile': 'https://Stackoverflow.com/users/10167', 'pm_score': 1, 'selected': False, 'text': '<p>Take a look at the Parser in the PHP Fit port.  The code is clean and was originally designed for loading the dirty HTML saved by Word.  It\'s configured to pull tables out, but can easily be adapated.</p>\n\n<p>You can see the source here:\n<a href="http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/Parser.phps" rel="nofollow noreferrer">http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/Parser.phps</a></p>\n\n<p>The unit test will show you how to use it:\n<a href="http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/test/parser.phps" rel="nofollow noreferrer">http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/test/parser.phps</a></p>\n'}, {'answer_id': 67691, 'author': 'Gilles', 'author_id': 10024, 'author_profile': 'https://Stackoverflow.com/users/10024', 'pm_score': 0, 'selected': False, 'text': '<p>My quick and dirty solution to this problem was to run a loop that matches my list of custom tags with a regular expression. The regexp doesn\'t catch tags that have another inner custom tag inside them. </p>\n\n<p>When there is a match, a function to process that tag is called and returns the "processed HTML". If that custom tag was inside another custom tag than the parent becomes childless by the fact that actual HTML was inserted in place of the child, and it will be matched by the regexp and processed at the next iteration of the loop. </p>\n\n<p>The loop ends when there are no childless custom tags to be matched. Overall it\'s iterative (a while loop) and not recursive.</p>\n'}, {'answer_id': 69383, 'author': 'nickf', 'author_id': 9021, 'author_profile': 'https://Stackoverflow.com/users/9021', 'pm_score': 0, 'selected': False, 'text': '<p>@Alan Storm</p>\n\n<p>Your comment on my other answer got me to thinking:</p>\n\n<blockquote>\n  <p>When you load an HTML file with DOMDocument, it appears to do some level of cleanup re: well well-formedness, BUT requires all your tags to be legit HTML tags. I\'m looking for something that does the former, but not the later. (Alan Storm)</p>\n</blockquote>\n\n<p>Run a regex (sorry!) over the tags, and when it finds one which isn\'t a valid HTML element, replace it with a valid element that you know doesn\'t exist in any of the documents (<code>blink</code> comes to mind...), and give it an attribute value with the name of the illegal element, so that you can switch it back afterwards. eg:</p>\n\n<pre><code>$code = str_replace("&lt;pseudo-tag&gt;", "&lt;blink rel=\\"pseudo-tag\\"&gt;", $code);\n// and then back again...\n$code = preg_replace(\'&lt;blink rel="(.*?)"&gt;\', \'&lt;\\1&gt;\', $code);\n</code></pre>\n\n<p>obviously that code won\'t work, but you get the general idea?</p>\n'}, {'answer_id': 3613335, 'author': 'troelskn', 'author_id': 18180, 'author_profile': 'https://Stackoverflow.com/users/18180', 'pm_score': 4, 'selected': True, 'text': '<p>You can suppress warnings with <a href="http://www.php.net/manual/en/function.libxml-use-internal-errors.php" rel="noreferrer"><code>libxml_use_internal_errors</code></a>, while loading the document. Eg.:</p>\n\n<pre><code>libxml_use_internal_errors(true);\n$doc = new DomDocument();\n$doc-&gt;loadHTML("&lt;strong&gt;This is an example of a &lt;pseud-template&gt;fake tag&lt;/pseud-template&gt;&lt;/strong&gt;");\nlibxml_use_internal_errors(false);\n</code></pre>\n\n<p>If, for some reason, you need access to the warnings, use <a href="http://www.php.net/manual/en/function.libxml-get-errors.php" rel="noreferrer"><code>libxml_get_errors</code></a></p>\n'}]
['https://Stackoverflow.com/questions/66727', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/4668/']