/**
* Attempt to parse a tag out of the content.
*
* @return array
*/
protected function parseTag()
{
$return = ['status' => false, 'closing' => false, 'node' => null];
if ($this->content->char() != '<') {
// we are not at the beginning of a tag
return $return;
}
// check if this is a closing tag
if ($this->content->fastForward(1)->char() == '/') {
// end tag
$tag = $this->content->fastForward(1)->copyByToken('slash', true);
// move to end of tag
$this->content->copyUntil('>');
$this->content->fastForward(1);
// check if this closing tag counts
$tag = strtolower($tag);
if (in_array($tag, $this->selfClosing)) {
$return['status'] = true;
return $return;
} else {
$return['status'] = true;
$return['closing'] = true;
$return['tag'] = strtolower($tag);
}
return $return;
}
$tag = strtolower($this->content->copyByToken('slash', true));
$node = new HtmlNode($tag);
// attributes
while ($this->content->char() != '>' and $this->content->char() != '/') {
$space = $this->content->skipByToken('blank', true);
if (empty($space)) {
break;
}
$name = $this->content->copyByToken('equal', true);
if ($name == '/' or empty($name)) {
break;
}
if (empty($name)) {
$this->content->fastForward(1);
continue;
}
$this->content->skipByToken('blank');
if ($this->content->char() == '=') {
$attr = [];
$this->content->fastForward(1)->skipByToken('blank');
switch ($this->content->char()) {
case '"':
$attr['doubleQuote'] = true;
$this->content->fastForward(1);
$attr['value'] = $this->content->copyUntil('"', false, true);
$this->content->fastForward(1);
$node->getTag()->{$name} = $attr;
break;
case "'":
$attr['doubleQuote'] = false;
$this->content->fastForward(1);
$attr['value'] = $this->content->copyUntil("'", false, true);
$this->content->fastForward(1);
$node->getTag()->{$name} = $attr;
break;
default:
$attr['doubleQuote'] = true;
$attr['value'] = $this->content->copyByToken('attr', true);
$node->getTag()->{$name} = $attr;
break;
}
} else {
// no value attribute
if ($this->options->strict) {
// can't have this in strict html
$character = $this->content->getPosition();
throw new StrictException("Tag '{$tag}' has an attribute '{$name}' with out a value! (character #{$character})");
}
$node->getTag()->{$name} = ['value' => null, 'doubleQuote' => true];
$this->content->rewind(1);
}
}
$this->content->skipByToken('blank');
if ($this->content->char() == '/') {
// self closing tag
$node->getTag()->selfClosing();
$this->content->fastForward(1);
} elseif (in_array($tag, $this->selfClosing)) {
// Should be a self closing tag, check if we are strict
if ($this->options->strict) {
$character = $this->content->getPosition();
throw new StrictException("Tag '{$tag}' is not self clossing! (character #{$character})");
}
// We force self closing on this tag.
$node->getTag()->selfClosing();
}
$this->content->fastForward(1);
$return['status'] = true;
$return['node'] = $node;
return $return;
}