tagStartOpen = "<"; $this->tagStartClose = ">"; $this->tagClose = "/>"; $this->tagEndOpen = "tagEndClose = ">"; $this->setTagName($name); $this->setTagContent($content); $this->tagAttributes = array(); $this->tagAttributeSeparator = " "; $this->tagAttributeSeparators = array(" ", "\n", "\r", "\t"); $this->tagAttributeAssignment = "="; $this->tagAttributeValueQuote = '"'; $this->FORMAT_NONE = 0; $this->FORMAT_INDENT = 1; $this->tagFormat = $this->FORMAT_NONE; $this->tagFormatIndentLevel = 0; $this->tagFormatEndTag = false; } /** * Find out whether attribute exists * @method attributeExists * @param string attrName * @returns true if attribute exists, false otherwise */ function attributeExists($attrName) { return array_key_exists($attrName, $this->tagAttributes); } /** * Get attribute value by its name * @method getTagAttribute * @param string attrName * @returns string attribute value */ function getTagAttribute($attrName) { return $this->tagAttributes[$attrName]; } /** * Get tag content string * @method getTagContent * @returns string tag content */ function getTagContent() { return $this->tagContent; } /** * Get tag name string * @method getTagName * @returns string tag name */ function getTagName() { return $this->tagName; } /** * Get complete tag string with its attributes and content * @method getTagString * @returns string tag string */ function getTagString() { $formatTagBegin = ""; $formatTagEnd = ""; $formatContent = ""; if($this->tagFormat == $this->FORMAT_INDENT) { if($this->tagFormatIndentLevel > 0) $formatTagBegin = $this->tagFormatNewLine . str_repeat($this->tagFormatIndent, $this->tagFormatIndentLevel); if($this->tagFormatEndTag) $formatTagEnd = $this->tagFormatNewLine . str_repeat($this->tagFormatIndent, $this->tagFormatIndentLevel); } $tagString = $formatTagBegin . $this->getTagStringBegin() . $formatContent . $this->tagContent . $formatTagEnd . $this->getTagStringEnd(); return $tagString; } /** * Get beginning of the tag string, i.e. its name attributes up until tag contents * @method getTagStringBegin * @returns string beginning of the tag string */ function getTagStringBegin() { $tagString = ""; if($this->tagName != "") { $tagString .= $this->tagStartOpen . $this->tagName; foreach($this->tagAttributes as $attrName => $attrValue) { $tagString .= $this->tagAttributeSeparator . $attrName . $this->tagAttributeAssignment . $this->tagAttributeValueQuote . $attrValue . $this->tagAttributeValueQuote; } if($this->tagContent == "") $tagString .= $this->tagAttributeSeparator . $this->tagClose; else $tagString .= $this->tagStartClose; } return $tagString; } /** * Get ending of the tag string, i.e. its closing tag * @method getTagStringEnd * @returns string close tag if tag is not short-handed, empty string otherwise */ function getTagStringEnd() { $tagString = ""; if($this->tagName != "" && $this->tagContent != "") $tagString .= $this->tagEndOpen . $this->tagName . $this->tagEndClose; return $tagString; } /** * Remove all tag attributes * @method removeAllAttributes * @returns none */ function removeAllAttributes() { $this->tagAttributes = array(); } /** * Remove a tag attribute by its name * @method removeAttribute * @returns none */ function removeAttribute($attrName) { unset($this->tagAttributes[$attrName]); } /** * Reset the tag object - set name, content to empty strings, and reset all attributes * @method resetTag * @returns none */ function resetTag() { $this->setTagName(""); $this->setTagContent(""); $this->removeAllAttributes(); } /** * Create or modify an existing attribute by supplying attribute name and value * @method setAttribute * @param string attrName * @param string attrValue * @returns none */ function setAttribute($attrName, $attrValue) { $this->tagAttributes[$attrName] = $attrValue; } /** * Set contents of the tag * @method setTagContent * @param string content * @returns none */ function setTagContent($content) { $this->tagContent = $content; } /** * Set tag formatting option by specifying tagFormat to 0 (none), or 1 (indented) * @method setTagFormat * @param int tagFormat * @param optional int tagFormatIndentLevel * @returns none */ function setTagFormat($tagFormat, $tagFormatIndentLevel = 0) { $this->tagFormat = $tagFormat; $this->tagFormatIndentLevel = $tagFormatIndentLevel; } /** * Set whether closing of the tag should be formatted or not * @method setTagFormatEndTag * @param optional boolean formatEndTag * @returns none */ function setTagFormatEndTag($formatEndTag = true) { $this->tagFormatEndTag = $formatEndTag; } /** * Parse a string containing a tag into the tag object, this will parse the first tag found * @method setTagFromString * @param string tagString * @returns array array of [0]=>index of the beginning of the tag, [1]=>index where tag ended */ function setTagFromString($tagString) { $i = 0; $j = 0; $tagStartOpen = $tagStartClose = $tagNameStart = $tagNameEnd = $tagContentStart = $tagContentEnd = $tagEndOpen = $tagEndClose = 0; $tagName = $tagContent = ""; $tagShort = false; $tagAttributes = array(); $success = true; $tagFound = false; while(!$tagFound && $i < strlen($tagString)) { // look for start tag character $i = strpos($tagString, $this->tagStartOpen, $i); if($i === false) break; // if tag name starts from alpha character we found the tag if(ctype_alpha(substr($tagString, $i + 1, 1))) $tagFound = true; // else continue searching else $i ++; } // if no tag found set success to false if(!$tagFound) $success = false; // if so far so good continue with found tag name if($success) { $tagStartOpen = $i; $tagNameStart = $i + 1; // search where tag name would end // search for a space separator to account for attributes $separatorPos = array(); for($counter = 0; $counter < count($this->tagAttributeSeparators); $counter ++) { $separatorPosTemp = strpos($tagString, $this->tagAttributeSeparators[$counter], $tagStartOpen); if($separatorPosTemp !== false) $separatorPos[] = $separatorPosTemp; } //$i = strpos($tagString, $this->tagAttributeSeparator, $tagStartOpen); if(count($separatorPos) > 0) $i = min($separatorPos); else $i = false; // search for tag close character $j = strpos($tagString, $this->tagStartClose, $tagStartOpen); // search for short tag (no content) $k = strpos($tagString, $this->tagClose, $tagStartOpen); // if tag close character is not found then no tag exists, set success to false if($j === false) $success = false; // if tag short close found before tag close, then tag is short if($k !== false && $k < $j) $tagShort = true; } // if so far so good set tag name correctly if($success) { // if space separator not found or it is found after the tag close char if($i === false || $i > $j) { if($tagShort) $tagNameEnd = $k; else $tagNameEnd = $j; $tagStartClose = $j; } // else if tag attributes exist else { $tagNameEnd = $i; $tagStartClose = $j; // parse attributes $tagAttributesStart = $i + strlen($this->tagAttributeSeparator); $attrString = trim(substr($tagString, $tagAttributesStart, $j - $tagAttributesStart)); $attrArray = explode($this->tagAttributeValueQuote, $attrString); $attrCounter = 0; while($attrCounter < count($attrArray) - 1) { $attributeName = trim(str_replace($this->tagAttributeAssignment, "", $attrArray[$attrCounter])); $attributeValue = $attrArray[$attrCounter + 1]; $tagAttributes[$attributeName] = $attributeValue; $attrCounter += 2; } } $tagName = rtrim(substr($tagString, $tagNameStart, $tagNameEnd - $tagNameStart)); if(!$tagShort) { $tagContentStart = $tagStartClose + 1; // look for ending of the tag after tag content $j = $tagContentStart; $tagCloseFound = false; // while loop will find the k-th tag close // start with one since we have one tag open $k = 1; while(!$tagCloseFound && $success) { // find k-th tag close from j $n = $j - 1; for($skip = 0; $skip < $k; $skip ++) { $n ++; $tempPos = strpos($tagString, $this->tagEndOpen . $tagName . $this->tagEndClose, $n); if($tempPos !== false) $n = $tempPos; else { $success = false; break; } } // if success, find number of tag opens before the tag close $k = 0; if($success) { $tempString = substr($tagString, $j, $n - $j); $tempNewPos = 0; do { $tempPos = strpos($tempString, $this->tagStartOpen . $tagName, $tempNewPos); if($tempPos !== false) { $tempPosChar = substr($tempString, $tempPos + strlen($this->tagStartOpen . $tagName), 1); $tagEndArray = $this->tagAttributeSeparators; $tagEndArray[] = $this->tagEndClose; $tempPosTagEnded = array_search($tempPosChar, $tagEndArray); if($tempPosTagEnded !== false && $tempPosTagEnded !== NULL) { $tempStartClose = strpos($tempString, $this->tagStartClose, $tempPos); $tempStartShortClose = strpos($tempString, $this->tagClose, $tempPos); // if open tag found increase counter if($tempStartClose !== false && ($tempStartShortClose === false || $tempStartClose < $tempStartShortClose)) $k ++; $tempNewPos = $tempPos + strlen($this->tagStartOpen . $tagName); } else $tempNewPos = $tempPos + strlen($this->tagStartOpen . $tagName); } } while($tempPos !== false); } // if no tags opened we found the tag close if($k == 0) $tagCloseFound = true; // else set new j else { $j = $n + strlen($this->tagEndOpen . $tagName . $this->tagEndClose); } } if($tagCloseFound) $i = $n; else $success = false; } } // if so far so good, then we have everything we need! set the object if($success) { if(!$tagShort) { $tagContentEnd = $i; $tagContent = substr($tagString, $tagContentStart, $tagContentEnd - $tagContentStart); $tagEndOpen = $i; $tagEndClose = $tagEndOpen + strlen($this->tagEndOpen . $tagName . $this->tagEndClose); } else $tagEndClose = $tagStartClose + strlen($this->tagStartClose); $this->setTagName($tagName); $this->setTagContent($tagContent); $this->tagAttributes = $tagAttributes; } if($success) return array($tagStartOpen, $tagEndClose); else return false; } /** * Set tag name * @method setTagName * @param string name * @returns none */ function setTagName($name) { $this->tagName = $name; } } ?>