closedquestion-8.x-3.x-dev/src/Utility/XmlLib.php
src/Utility/XmlLib.php
<?php
namespace Drupal\closedquestion\Utility;
use Drupal\closedquestion\Question\CqQuestionInterface;
/**
* Class XmlLib.
*
* @package Drupal\closedquestion\Utility
*/
class XmlLib {
/**
* Copy all the attributes of $node into a HTML attribute string.
*
* @param object $node
* XML node to copy all the attributes from.
*
* @return string
* String containing the attributes.
*/
public function copyAttributes($node) {
$retval = '';
foreach ($node->attributes as $attr_name => $attr_node) {
$retval .= ' ' . $attr_name . '="' . $attr_node->nodeValue . '"';
}
return $retval;
}
/**
* Recursively parse the children of an XML node.
*
* This function returns the parts that are
* valid html. The context CqQuestionInterface object can provide a list of
* node names that are not html, but can be turned into html by the context
* object.
*
* If fullFilter is set, the final html will be filtered through the Drupal
* filter set of the context CqQuestionInterface.
*
* @param \DOMNode $parent
* The XML node to parse the children of.
* @param \Drupal\closedquestion\Question\CqQuestionInterface $context
* The question that can supply extra node names to handle, and drupal
* filters.
* @param bool $full_filter
* Filter the result also through the drupal content filters?
* @param bool $delay
* If true, some XML nodes are replaced with a [] tag so they can be
* processed later. This can be used when not all data needed for full
* processing is available yet.
* Important: If delay is TRUE then the text is NOT filtered through the
* Drupal content filters until after a call to cq_replace_tags().
*
* @return string
* The html contained in the node.
*/
public function getTextContent(\DOMNode $parent, CqQuestionInterface $context, $full_filter = TRUE, $delay = FALSE) {
$retval = '';
$nodes = $parent->childNodes;
if (\Drupal::config('closedquestion.settings')->get('use_xml_filter') == TRUE) {
foreach ($nodes as $node) {
switch ($node->nodeName) {
case '#comment':
break;
case '#text':
case '#cdata-section':
$retval .= $node->nodeValue;
break;
case 'formblock':
$retval .= '<formblock/>';
break;
case 'img':
case 'br':
$retval .= '<' . $node->nodeName . ' ' . $this->copyAttributes($node) . '/>';
break;
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
case 'sub':
case 'sup':
case 'p':
case 'pre':
case 'b':
case 'i':
case 'u':
case 'strong':
case 'em':
case 'table':
case 'tbody':
case 'thead':
case 'a':
case 'tr':
case 'td':
case 'th':
case 'span':
case 'div':
case 'ul':
case 'ol':
case 'dl':
case 'dt':
case 'dd':
case 'li':
case 'blockquote':
case 'cite':
$retval .= '<' . $node->nodeName . ' ' . $this->copyAttributes($node) . '>' . $this->getTextContent($node, $context, FALSE, $delay) . '</' . $node->nodeName . '>';
break;
default:
$retval .= $node->nodeValue;
break;
}
foreach ($context->getHandledTags() as $tag) {
if (mb_strtolower($node->nodeName) == mb_strtolower($tag)) {
$retval .= $context->handleNode($node, $delay);
}
}
}
}
else {
foreach ($nodes as $node) {
// A bool is used to indicated wheter the node is already handled.
$handled = FALSE;
foreach ($context->getHandledTags() as $tag) {
if (mb_strtolower($node->nodeName) == mb_strtolower($tag)) {
$retval .= $context->handleNode($node, $delay);
$handled = TRUE;
}
}
// If the node is not handled handle it now.
if ($handled == FALSE) {
// If the node has children parse them.
if ($node->hasChildNodes() && $node->nodeName != '#cdata-section') {
$retval .= '<' . $node->nodeName . ' ' . $this->copyAttributes($node) . '>' . $this->getTextContent($node, $context, FALSE, $delay) . '</' . $node->nodeName . '>';
}
// Otherwise return the string representation of the node.
else {
$retval .= $node->ownerDocument->saveXML($node);
}
}
}
}
if ($full_filter && !$delay) {
$closedquestion = $context->getClosedQuestion();
$retval = check_markup(trim($retval), $closedquestion->get('field_question_xml')->format, FALSE);
}
return $retval;
}
/**
* Search through the text for any occurrences of [tagName|tagData].
*
* If any are found, and tagName is a registered tag name, then let the
* context handle the tag.
*
* @param string $text
* The text to parse for tags.
* @param \Drupal\closedquestion\Question\CqQuestionInterface $context
* The question that can supply extra tag names to handle.
*
* @return \Drupal\Component\Render\MarkupInterface|mixed|string
* Processed text.
*/
public function replaceTags($text, CqQuestionInterface $context = NULL) {
if (preg_match_all("/\[([a-zA-Z]+)\|([^]]*)]/i", $text, $match)) {
$s = array();
$r = array();
foreach ($match[1] as $key => $value) {
$replace = $context->handleTag($value, $match[2][$key]);
$s[] = $match[0][$key];
$r[] = $replace;
}
// Perform the replacements and return processed field.
$text = str_replace($s, $r, $text);
}
if ($context) {
$closedquestion = $context->getClosedQuestion();
$text = (string) check_markup(trim($text), $closedquestion->get('field_question_xml')->first()->getValue()['format'], FALSE);
}
return $text;
}
}
