当<html>,<head>,<body>标记未设置时,将PHP DOM设置为不正确的html

He I have made this function to set attributes on id:

function set_atr($id, $attribute, $value, $source){

    $dom = new DomDocument();

    $dom->loadHTML('<meta http-equiv="content-type" content="text/html; charset=utf-8">'.$source);

    $xp = new DOMXPath($dom);
    $element = $xp->query('//*[@id="'.$id.'"]')->item(0);

    if(!$element){
        return false;
    }
    else{
        $element->setAttribute($attribute, $value);
        return str_replace('<meta http-equiv="content-type" content="text/html; charset=utf-8">', '', $dom->saveHTML($dom->documentElement));
    }
}

When I don't use this to edit the entire document but just a snap of it like:

<table>
    <tr>
            <td><h4>login</h4></td>
            <td></td>
    </tr>
    <tr>
        <td>username:</td>
        <td>password:</td>
    </tr>
    <tr>
        <td><input id="username" type="text" placeholder="pipo" name="username" class="form" /></td>
        <td><input id="password" type="password" placeholder="wachtwoord" name="password" class="form" /></td>
    </tr>
    <tr>
        <td id="error1"></td>
        <td id="error2"></td>
    </tr>
    <tr>
        <td><input type="button" value="Login" class="btn" action="url" level="cms_user_login" form="login" /></td>
        <td></td>
    </tr>
</table>

it assumes that the rest of the document is missing and it adds the additional html tags like this:

<html>
<head></head>
<body>    <table>
    <tr>
            <td><h4>login</h4></td>
            <td></td>
    </tr>
    <tr>
        <td>username:</td>
        <td>password:</td>
    </tr>
    <tr>
        <td><input id="username" type="text" placeholder="pipo" name="username" class="form" /></td>
        <td><input id="password" type="password" placeholder="wachtwoord" name="password" class="form" /></td>
    </tr>
    <tr>
        <td id="error1"></td>
        <td id="error2"></td>
    </tr>
    <tr>
        <td><input type="button" value="Login" class="btn" action="url" level="cms_user_login" form="login" /></td>
        <td></td>
    </tr>
</table></body>
</html>

It does not hurt directly but it looks ugly. The reason I use it this way is because I use ajax a lot and I only send back a snippet of the html not a whole document.

So anyone knows how to make DOM stop doing this? Or is this impossible. I can also just use str_replace to delete them when I use my function but I consider that a ugly fix.

Adding the <meta> tag will trigger the fixing behavior of DOMDocument. The good part is that you don't need to add that tag at all. If you wan't to use an encoding of your choosing just pass it as a constructor argument.

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

Output

<div>Hello World</div>

If you're using Libxml >= 2.7.7 (as of PHP >= 5.4.0) call loadHTML with LIBXML_HTML_NOIMPLIED as the second argument. E.g.

$dom->loadHTML($source, LIBXML_HTML_NOIMPLIED);

This will suppress the addition of the implied <html> and <body> elements.

Also see this answer.