static function getOutputData( $title, $rid = 0 ) {
		// normal page
		global $wgTitle, $wgUser;
		$wgTitle = $title;
		$revision = Revision::newFromTitle( $title, $rid );
		if ( $revision === NULL ) {
			throw new MWException( __METHOD__ . ": Page not exist '{$page_name} ({$rid})'" );
		}
		$text = $revision->getText();
		$wom = WOMProcessor::parseToWOM( $text );

		global $wgOMOutputHookedParserFunctions;
		$pfs = $wom->getObjectsByTypeID( WOM_TYPE_PARSERFUNCTION );
		foreach ( $pfs as $id => $obj ) {
			self::removeSubWOMIds( $obj );
			foreach ( $wgOMOutputHookedParserFunctions as $function_key ) {
				if ( $obj->getFunctionKey() == $function_key ) {
					// add wom id to parser function, with specified parameter 'wom_id'
					$param = new WOMParameterModel( 'wom_id' );
					$pv = new WOMParamValueModel();
					$param->insertObject( $pv );
					$pv->insertObject( new WOMTextModel( $id ) );
					$obj->insertObject( $param );
				}
			}
		}
		// FIXME: template values may have object ids
		$tmpls = $wom->getObjectsByTypeID( WOM_TYPE_TEMPLATE );
		foreach ( $tmpls as $id => $obj ) {
			self::removeSubWOMIds( $obj );
		}

		global $wgParser, $wgOut, $wgWOMOutputHooked;
		$wgWOMOutputHooked = true;
		$options = ParserOptions::newFromUser( $wgUser );

		self::$queryProps = array();
		self::$queryId = 1;
		$wgParser->parse( $wom->getWikiText(), $title, $options );

		$output = SMWParseData::getSMWdata( $wgParser );

		if ( !isset( $output ) ) {
			$semdata = smwfGetStore()->getSemanticData( $title );
		} else {
			$semdata = $output;
		}

		$tmp_id = 0;
		// fill in semantic properties
		$properties = array();
		foreach ( $semdata->getProperties() as $property ) {
			$label = '';
			if ( !$property->isShown() ) { // showing this is not desired, hide
				continue;
			} elseif ( $property->isUserDefined() ) { // user defined property
				if ( version_compare ( SMW_VERSION, '1.6', '>=' ) ) {
					$label = $property->getLabel();
				} else {
					$property->setCaption( preg_replace( '/[ ]/u', ' ', $property->getWikiValue(), 2 ) );
					// / NOTE: the preg_replace is a slight hack to ensure that the left column does not get too narrow
					$label = $property->getWikiValue();
				}
			} else {
				if ( version_compare ( SMW_VERSION, '1.6', '>=' ) ) {
					$label = $property->getLabel();
				} else {
					if ( $property->isVisible() ) { // predefined property
						$label = $property->getWikiValue();
					} else { // predefined, internal property
						continue;
					}
				}
			}
			$properties[$label] = array();

			$propvalues = $semdata->getPropertyValues( $property );
			foreach ( $propvalues as $propvalue ) {
				if ( version_compare ( SMW_VERSION, '1.6', '>=' ) ) {
					if ( $propvalue->getDIType() == SMWDataItem::TYPE_ERROR ) continue;
					$properties[$label][$propvalue->getSerialization()] = false;
				} else {
					$properties[$label][$propvalue->getWikiValue()] = false;
				}
			}
		}
		$props = $wom->getObjectsByTypeID( WOM_TYPE_PROPERTY );
		foreach ( $props as $prop ) {
			$id = $prop->getObjectID();
			if ( $id == '' ) continue;
			$name = $prop->getPropertyName();
			$value = $prop->getPropertyValue();
			if ( !isset( $properties[$name][$value] ) ) {
				// remove category not match to output
				$wom->removePageObject( $id );
			} else {
				$properties[$name][$value] = true;
			}
		}
		foreach ( $properties as $name => $values ) {
			foreach ( $values as $val => $flag ) {
				if ( $flag !== true ) {
					$p = new WOMPropertyModel( $name, $val );
					$p->setObjectID( 'output' . ( $tmp_id ++ ) );
					$wom->insertObject( $p );
					$wom->addToPageObjectSet( $p );
				}
			}
		}

		// fill in ask query results
		foreach ( self::$queryProps as $wom_id => $queries ) {
			$query_res = new WOMQueryResult();
			if ( $wom_id != '' ) {
				$parent = $wom->getObject( $wom_id );
			} else {
				$parent = new WOMParserFunctionModel( 'ask' );
				$parent->setObjectID( 'output' . ( $tmp_id ++ ) );
				$wom->insertObject( $parent );
				$wom->addToPageObjectSet( $parent );
			}
			$parent->insertObject( $query_res );
			$query_res->setObjectID( 'output' . ( $tmp_id ++ ) );
			$wom->addToPageObjectSet( $query_res );
			foreach ( $queries as $label => $vals ) {
				$vals = array_unique( $vals );
				foreach ( $vals as $val ) {
					$query_res->insertObject( new WOMPropertyModel( $label, $val ) );
				}
			}
		}

		// fill in categories
		$categories = $title->getParentCategories();
		$cates = $wom->getObjectsByTypeID( WOM_TYPE_CATEGORY );
		foreach ( $cates as $cate ) {
			$id = $cate->getObjectID();
			if ( $id == '' ) continue;
			$name = Title::newFromText( $cate->getName(), NS_CATEGORY )->getFullText();
			if ( !isset( $categories[$name] ) ) {
				// remove category not match to output
				$wom->removePageObject( $id );
			} else {
				$categories[$name] = true;
			}
		}
		foreach ( $categories as $cate => $flag ) {
			if ( $flag !== true ) {
				$c = new WOMCategoryModel( Title::newFromText( $cate )->getText() );
				$c->setObjectID( 'output' . ( $tmp_id ++ ) );
				$wom->insertObject( $c );
				$wom->addToPageObjectSet( $c );
			}
		}

		return $wom;
	}
    public function execute()
    {
        global $wgUser;
        $params = $this->extractRequestParams();
        if (is_null($params['title'])) {
            $this->dieUsage('Must specify page title', 0);
        }
        if (is_null($params['xpath'])) {
            $this->dieUsage('Must specify xpath', 1);
        }
        $page_name = $params['title'];
        $xpath = $params['xpath'];
        $type = $params['type'];
        $rid = $params['rid'];
        $articleTitle = Title::newFromText($page_name);
        if (!$articleTitle) {
            $this->dieUsage("Can't create title object ({$page_name})", 2);
        }
        $article = new Article($articleTitle);
        if (!$article->exists()) {
            $this->dieUsage("Article doesn't exist ({$page_name})", 3);
        }
        $page_obj = WOMOutputProcessor::getOutputData($articleTitle, $rid);
        try {
            $objs = WOMProcessor::getObjIdByXPath2($page_obj, $xpath);
        } catch (Exception $e) {
            $err = $e->getMessage();
        }
        $result = array();
        if (isset($err)) {
            $result = array('result' => 'Failure', 'message' => array());
            $this->getResult()->setContent($result['message'], $err);
        } else {
            $result['result'] = 'Success';
            // pay attention to special xml tag, e.g., <property><value>...</value></property>
            $result['return'] = array();
            if ($type == 'count') {
                $count = 0;
                foreach ($objs as $id) {
                    if ($id == '') {
                        continue;
                    }
                    ++$count;
                }
                $this->getResult()->setContent($result['return'], $count);
            } else {
                $xml = '';
                foreach ($objs as $id) {
                    if ($id == '') {
                        continue;
                    }
                    $wobj = $page_obj->getObject($id);
                    $result['return'][$id] = array();
                    if ($type == 'xml') {
                        $xml .= "<{$id} xml:space=\"preserve\">{$wobj->toXML()}</{$id}>";
                    } else {
                        $this->getResult()->setContent($result['return'][$id], $wobj->getWikiText());
                    }
                }
                if ($type == 'xml') {
                    header("Content-Type: application/rdf+xml");
                    echo <<<OUTPUT
<?xml version="1.0" encoding="UTF-8" ?>
<api><womoutput result="Success"><return>
{$xml}
</return></womoutput></api>
OUTPUT;
                    exit(1);
                }
            }
        }
        $this->getResult()->addValue(null, $this->getModuleName(), $result);
    }