Skip to content
Waseem Sadiq edited this page May 5, 2020 · 19 revisions

Pages has robust support for pulling XML values. The following are different ways to access different parts of an XML file.

Get

If you need a direct full path then GET is used.

<?= data('volume-1/issue-1/tomo-01-069')->get('article/front/journal-meta/journal-title-group/journal-title'); ?>

Find

If there are no other conflicting labels then you can access the value directly using FIND. This is a massive time saver since you don't have to traverse through each level like you do with GET.

<?= data('volume-1/issue-1/tomo-01-069')->find('journal-title'); ?>

Attributes

If your XML uses attributes then you access the values using the filter for attributes.

<?= data('volume-1/issue-1/JSHD-201800011')->get('article/front/article-meta/article-id')->filter('@attributes', ['pub-id-type' => 'publisher-id']); ?>
<?= data('volume-1/issue-1/JSHD-201800011')->find('subj-group')->filter('@attributes', ['subj-group-type' => 'Article Type'])->subject; ?>

Adding Defaults

If you are using YAML with XML fallback you can set it to default to YAML, then fall back to XML.

$title = $this->title ?? $this->data('volume-1/issue-1/tomo-01-069')->get('article/front/article-meta/title-group/article-title');

Note: This example is within a function which is why $this-> is added.

Output options

If you echo the XML data it will pull it as an array. Pages will then transform it to JSON. This saves a few steps if you are needing to separate the output by content within tags in the XML. For example with this line of XML <aff id="aff1">Departments of <label>1</label>Radiology</aff>. This example is for a list of affiliations with reference numbers, so I am looping through each of them and constructing the output.

if ( $this->data( $this->article_xml('data-path') )->find('aff') !== '' ) {
    foreach ( $this->data( $this->article_xml('data-path') )->find('aff') as $aff ) :
        if ( isset( $aff['label'] ) ) {
            $sup = "<sup>" . $aff['label'] . "</sup>";
        }
        $affiliations .= $sup . $aff['@text'];
    endforeach;
}

If you want to pull the data and output it as HTML then add ->asHtml to the end.

$abstract = $this->publishing['abstract'] ?? $this->data( $this->article_xml('data-path') )->find('abstract')->toHtml();

Selecting node by CSS

If you have CSS in your node you would like to select you can using the select option. This is gonna return a nodelist, however there are plans to update it to a string in the future.

$list = data('test-xml')->toHtml()->select('affs.aff1');

Creating dynamic paths to XML

For the project in these examples the site is set up with volume, issues, and articles within each issue. XML files are organized in this file structure so it is necessary to dynamically pull each XML file according to which article is being viewed. This function has a switch that allows you to pull the path for other reasons or load the XML file by default.

return function( $type = '' )
{
    $volume = $this->volume();
    $issue  = $this->issue();

    $prefix        = $this->data('site-info')->file_prefix;
    $starting_page = $this->page()->publishing['starting_page'];

    //Article data
    $file_name = sprintf("%s-%02d-%03d", $prefix, $volume, $starting_page);
    $file_name = $this->page()->get('file', $file_name);
    $data_path = sprintf('volume-%s/issue-%s/%s', $volume, $issue, $file_name);

    if ( $type == 'data-path' ) {
        $data = $data_path;
    } else {
        $data = $this->data($data_path);
    }

	return $data;
};

XSL

Commenting on every part of this would take quite a bit of time, but here is a function to transform your XML into XSL. Modify as needed.

use BetterDOMDocument\DOMDoc;

return function()
{
	$volume = $this->volume();
	$issue  = $this->issue();

	$prefix        = $this->data('site-info')->file_prefix;
	$starting_page = $this->page()->publishing['starting_page'];

	//Article data
	$file_name = sprintf("%s-%02d-%03d", $prefix, $volume, $starting_page);
	$file_name = $this->page()->get('file', $file_name);
	$data_path = sprintf('volume-%s/issue-%s/%s', $volume, $issue, $file_name);

	/* Load XML file in a way str_replace will work on, save as variable, then close file */
        $xml_file_path = JPATH_ROOT.'/joomlatools-pages/data/' . $data_path . '.xml';
        $xml_file_temp = fopen( $xml_file_path, 'r');
	$xml_content = fread($xml_file_temp, filesize( $xml_file_path ));
	fclose($xml_file_temp);

	/* Replacing content in XML for better HTML output with XSL */
	// Trim whitespace
	$xml_updated_content = preg_replace("/>s+</", "><", $xml_content);

	// Change URL to images
	$base = ltrim($this->getObject('request')->getBaseUrl()->getPath(), '/');
	$xml_updated_content = str_replace('xlink:href="assets', 'xlink:href="'.$base.'/joomlatools-pages/assets', $xml_content);

	// Make sure there is space between first and last names
	$xml_updated_content = str_replace("</surname><given-names>", "</surname> <given-names>", $xml_updated_content);
	$xml_updated_content = str_replace("</given-names><suffix>", "</given-names> <suffix>", $xml_updated_content);

	$xml = new DOMDocument('1.0', 'UTF-8');
	$xml->loadXml( $xml_updated_content );

	/* Time for some XSL! */
	$xsl = new  DOMDocument('1.0', 'UTF-8');
	$xsl->loadXml(file_get_contents(JPATH_ROOT.'/joomlatools-pages/layouts/xsl/jats-html-mod.xsl'));
	$proc = new XSLTProcessor();
	$proc->importStyleSheet($xsl); // attach the xsl rules
	$html = $proc->transformToXML($xml);

	return $html;
};

Previous: Articles | Next: Forms

Clone this wiki locally