/** * 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; }
public function testCopyByToken() { $content = new Content('<a href="google.com">'); $content->fastForward(3); $this->assertEquals('href="google.com"', $content->copyByToken('attr', true)); }