xmlNode = $xmlNode; $this->infoboxData = $infoboxData; } public function getSource() { return $this->extractSourceFromNode( $this->xmlNode ); } /** * @return ExternalParser */ public function getExternalParser() { if ( !isset( $this->externalParser ) ) { $this->setExternalParser( new SimpleParser() ); } return $this->externalParser; } /** * @param ExternalParser|null $externalParser * * @return $this */ public function setExternalParser( $externalParser ) { // we can pass anything, and ignore it if not ExternalParser instance // we use builder pattern here, for fluently passing external parser to children nodes, // type hinting was removed to prevent catchable fatal error appearing if ( $externalParser instanceof ExternalParser ) { $this->externalParser = $externalParser; } return $this; } public function getType() { /* * Node type generation is based on XML tag name. * It's worth to remember that SimpleXMLElement::getName method is * case - sensitive ( "" != "" ), so we need to sanitize Node Type * by using mb_strtolower function */ return mb_strtolower( $this->xmlNode->getName() ); } public function isType( $type ) { return strcmp( $this->getType(), mb_strtolower( $type ) ) == 0; } public function getData() { if ( !isset( $this->data ) ) { $this->data = [ 'value' => (string)$this->xmlNode ]; } return $this->data; } public function getRenderData() { return [ 'type' => $this->getType(), 'data' => $this->getData(), ]; } /** * @desc Check if node is empty. * Note that a '0' value cannot be treated like a null * * @return bool */ public function isEmpty() { $data = $this->getData()[ 'value' ]; return ( empty( $data ) && $data != '0' ); } protected function getChildNodes() { if ( !isset( $this->children ) ) { $this->children = [ ]; foreach ( $this->xmlNode as $child ) { $this->children[ ] = NodeFactory::newFromSimpleXml( $child, $this->infoboxData ) ->setExternalParser( $this->externalParser ); } } return $this->children; } protected function getDataForChildren() { return array_map( function ( Node $item ) { return [ 'type' => $item->getType(), 'data' => $item->getData(), 'isEmpty' => $item->isEmpty(), 'source' => $item->getSource() ]; }, $this->getChildNodes() ); } protected function getRenderDataForChildren() { return array_map( function ( Node $item ) { return $item->getRenderData(); }, array_filter( $this->getChildNodes(), function ( Node $item ) { return !$item->isEmpty(); } ) ); } protected function getSourceForChildren() { /** @var Node $item */ $result = [ ]; foreach ( $this->getChildNodes() as $item ) { $result = array_merge( $result, $item->getSource() ); } return array_unique( $result ); } protected function getValueWithDefault( \SimpleXMLElement $xmlNode ) { $value = $this->extractDataFromSource( $xmlNode ); if ( !$value && $xmlNode->{self::DEFAULT_TAG_NAME} ) { return $this->extractDataFromNode( $xmlNode->{self::DEFAULT_TAG_NAME} ); } if ( $value && $xmlNode->{self::FORMAT_TAG_NAME} ) { return $this->extractDataFromNode( $xmlNode->{self::FORMAT_TAG_NAME} ); } return $value; } protected function getRawValueWithDefault( \SimpleXMLElement $xmlNode ) { $value = $this->getRawInfoboxData( $this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME ) ); if ( !$value && $xmlNode->{self::DEFAULT_TAG_NAME} ) { $value = $this->getExternalParser()->replaceVariables( (string)$xmlNode->{self::DEFAULT_TAG_NAME} ); } return $value; } protected function getValueWithData( \SimpleXMLElement $xmlNode ) { $value = $this->extractDataFromSource( $xmlNode ); return $value ? $value : $this->extractDataFromNode( $xmlNode ); } protected function getInnerValue( \SimpleXMLElement $xmlNode ) { return $this->getExternalParser()->parseRecursive( SimpleXmlUtil::getInstance()->getInnerXML( $xmlNode ) ); } protected function getXmlAttribute( \SimpleXMLElement $xmlNode, $attribute ) { return ( isset( $xmlNode[ $attribute ] ) ) ? (string)$xmlNode[ $attribute ] : null; } protected function getRawInfoboxData( $key ) { return isset( $this->infoboxData[ $key ] ) ? $this->infoboxData[ $key ] : null; } protected function getInfoboxData( $key ) { return $this->getExternalParser()->parseRecursive( $this->getRawInfoboxData( $key ) ); } /** * @param \SimpleXMLElement $xmlNode * * @return mixed */ protected function extractDataFromSource( \SimpleXMLElement $xmlNode ) { $source = $this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME ); return ( !empty( $source ) ) ? $this->getInfoboxData( $source ) : null; } /** * @param \SimpleXMLElement $xmlNode * * @return string */ protected function extractDataFromNode( \SimpleXMLElement $xmlNode ) { /* * tag can contain or other WikiText parser hooks * We should not parse it's contents as XML but return pure text in order to let MediaWiki Parser * parse it. */ return $this->getExternalParser()->parseRecursive( SimpleXmlUtil::getInstance()->getInnerXML( $xmlNode ) ); } /** * @param \SimpleXMLElement $xmlNode * * @return array * */ protected function extractSourceFromNode( \SimpleXMLElement $xmlNode ) { $source = $this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME ) ? [$this->getXmlAttribute( $xmlNode, self::DATA_SRC_ATTR_NAME )] : []; if ( $xmlNode->{self::FORMAT_TAG_NAME} ) { $source = $this->matchVariables( $xmlNode->{self::FORMAT_TAG_NAME}, $source ); } if ( $xmlNode->{self::DEFAULT_TAG_NAME} ) { $source = $this->matchVariables( $xmlNode->{self::DEFAULT_TAG_NAME}, $source ); } return $source; } protected function matchVariables( \SimpleXMLElement $node, array $source ) { preg_match_all( self::EXTRACT_SOURCE_REGEX, (string)$node, $sources ); return array_unique( array_merge( $source , $sources[ 1 ] ) ); } }