You are here

protected function EasyRdf_Parser_Rdfa::processNode in Zircon Profile 8.0

Same name and namespace in other branches
  1. 8 vendor/easyrdf/easyrdf/lib/EasyRdf/Parser/Rdfa.php \EasyRdf_Parser_Rdfa::processNode()
1 call to EasyRdf_Parser_Rdfa::processNode()
EasyRdf_Parser_Rdfa::parse in vendor/easyrdf/easyrdf/lib/EasyRdf/Parser/Rdfa.php
Parse RDFa 1.1 into an EasyRdf_Graph

File

vendor/easyrdf/easyrdf/lib/EasyRdf/Parser/Rdfa.php, line 298

Class

EasyRdf_Parser_Rdfa
Class to parse RDFa 1.1 with no external dependancies.

Code

protected function processNode($node, &$context, $depth = 1) {
  if ($this->debug) {
    $this
      ->printNode($node, $depth);
  }

  // Step 1: establish local variables
  $skip = false;
  $subject = null;
  $typedResource = null;
  $object = null;
  $rels = array();
  $revs = array();
  $lang = $context['lang'];
  $incompleteRels = array();
  $incompleteRevs = array();
  if ($node->nodeType === XML_ELEMENT_NODE) {
    $context['path'] .= '/' . $node->nodeName;
    $content = $node
      ->hasAttribute('content') ? $node
      ->getAttribute('content') : null;
    $datatype = $node
      ->hasAttribute('datatype') ? $node
      ->getAttribute('datatype') : null;
    $property = $node
      ->getAttribute('property') ? $node
      ->getAttribute('property') : null;
    $typeof = $node
      ->getAttribute('typeof') ? $node
      ->getAttribute('typeof') : null;

    // Step 2: Default vocabulary
    if ($node
      ->hasAttribute('vocab')) {
      $context['vocab'] = $node
        ->getAttribute('vocab');
      if ($context['vocab']) {
        $this
          ->addTriple($this->baseUri, 'rdfa:usesVocabulary', array(
          'type' => 'uri',
          'value' => $context['vocab'],
        ));
      }
    }

    // Step 3: Set prefix mappings
    // Support for deprecated xmlns if present in document
    foreach ($context['xmlns'] as $prefix => $uri) {
      if ($node
        ->hasAttribute('xmlns:' . $prefix)) {
        $context['prefixes'][$prefix] = $node
          ->getAttribute('xmlns:' . $prefix);
        if ($this->debug) {
          print "Prefix (xmlns): {$prefix} => {$uri}\n";
        }
      }
    }
    if ($node
      ->hasAttribute('prefix')) {
      $mappings = preg_split('/\\s+/', $node
        ->getAttribute('prefix'));
      while (count($mappings)) {
        $prefix = strtolower(array_shift($mappings));
        $uri = array_shift($mappings);
        if (substr($prefix, -1) === ':') {
          $prefix = substr($prefix, 0, -1);
        }
        else {
          continue;
        }
        if ($prefix === '_') {
          continue;
        }
        elseif (!empty($prefix)) {
          $context['prefixes'][$prefix] = $uri;
          if ($this->debug) {
            print "Prefix: {$prefix} => {$uri}\n";
          }
        }
      }
    }

    // Step 4
    if ($node
      ->hasAttributeNS(self::XML_NS, 'lang')) {
      $lang = $node
        ->getAttributeNS(self::XML_NS, 'lang');
    }
    elseif ($node
      ->hasAttribute('lang')) {
      $lang = $node
        ->getAttribute('lang');
    }

    // HTML+RDFa 1.1: ignore rel and rev unless they contain CURIEs.
    foreach (array(
      'rel',
      'rev',
    ) as $attr) {
      if ($node
        ->hasAttribute('property') and $node
        ->hasAttribute($attr)) {

        // Quick check in case there are no CURIEs to deal with.
        if (strpos($node
          ->getAttribute($attr), ':') === false) {
          $node
            ->removeAttribute($attr);
        }
        else {

          // Only keep CURIEs.
          $curies = array();
          foreach (preg_split('/\\s+/', $node
            ->getAttribute($attr)) as $token) {
            if (strpos($token, ':')) {
              $curies[] = $token;
            }
          }
          $node
            ->setAttribute($attr, implode(' ', $curies));
        }
      }
    }
    $rels = $this
      ->processUriList($node, $context, $node
      ->getAttribute('rel'));
    $revs = $this
      ->processUriList($node, $context, $node
      ->getAttribute('rev'));
    if (!$node
      ->hasAttribute('rel') and !$node
      ->hasAttribute('rev')) {

      // Step 5: Establish a new subject if no rel/rev
      if ($property and is_null($content) and is_null($datatype)) {
        $subject = $this
          ->getUriAttribute($node, $context, 'about');
        if ($typeof and !$subject) {
          $typedResource = $this
            ->getUriAttribute($node, $context, array(
            'resource',
            'href',
            'src',
          ));
          if (!$typedResource) {
            $typedResource = $this->graph
              ->newBNodeId();
          }
          $object = $typedResource;
        }
      }
      else {
        $subject = $this
          ->getUriAttribute($node, $context, array(
          'about',
          'resource',
          'href',
          'src',
        ));
      }

      // Establish a subject if there isn't one

      # FIXME: refactor this
      if (is_null($subject)) {
        if ($context['path'] === '/html/head') {
          $subject = $context['object'];
        }
        elseif ($depth <= 2) {
          $subject = $this->baseUri;
        }
        elseif ($typeof and !$property) {
          $subject = $this->graph
            ->newBNodeId();
        }
        else {
          if (!$property) {
            $skip = true;
          }
          $subject = $context['object'];
        }
      }
    }
    else {

      // Step 6
      // If the current element does contain a @rel or @rev attribute, then the next step is to
      // establish both a value for new subject and a value for current object resource:
      $subject = $this
        ->getUriAttribute($node, $context, 'about');
      $object = $this
        ->getUriAttribute($node, $context, array(
        'resource',
        'href',
        'src',
      ));
      if ($typeof) {
        if (!$object and !$subject) {
          $object = $this->graph
            ->newBNodeId();
        }
        $typedResource = $subject ? $subject : $object;
      }

      # FIXME: if the element is the root element of the document

      # then act as if there is an empty @about present
      if (!$subject) {
        $subject = $context['object'];
      }
    }

    # FIXME: better place for this?
    if ($typeof and $subject and !$typedResource) {
      $typedResource = $subject;
    }

    // Step 7: Process @typeof if there is a subject
    if ($typedResource) {
      foreach ($this
        ->processUriList($node, $context, $typeof) as $type) {
        $this
          ->addTriple($typedResource, 'rdf:type', array(
          'type' => 'uri',
          'value' => $type,
        ));
      }
    }

    // Step 8: Create new List mapping if the subject has changed
    if ($subject and $subject !== $context['subject']) {
      $listMapping = new StdClass();
    }
    else {
      $listMapping = $context['listMapping'];
    }

    // Step 9: Generate triples with given object
    if ($subject and $object) {
      foreach ($rels as $prop) {
        $obj = array(
          'type' => 'uri',
          'value' => $object,
        );
        if ($node
          ->hasAttribute('inlist')) {
          $this
            ->addToList($listMapping, $prop, $obj);
        }
        else {
          $this
            ->addTriple($subject, $prop, $obj);
        }
      }
      foreach ($revs as $prop) {
        $this
          ->addTriple($object, $prop, array(
          'type' => 'uri',
          'value' => $subject,
        ));
      }
    }
    elseif ($rels or $revs) {

      // Step 10: Incomplete triples and bnode creation
      $object = $this->graph
        ->newBNodeId();
      if ($rels) {
        if ($node
          ->hasAttribute('inlist')) {
          foreach ($rels as $prop) {

            # FIXME: add support for incomplete lists
            if (!isset($listMapping->{$prop})) {
              $listMapping->{$prop} = array();
            }
          }
        }
        else {
          $incompleteRels = $rels;
          if ($this->debug) {
            print "Incomplete rels: " . implode(',', $rels) . "\n";
          }
        }
      }
      if ($revs) {
        $incompleteRevs = $revs;
        if ($this->debug) {
          print "Incomplete revs: " . implode(',', $revs) . "\n";
        }
      }
    }

    // Step 11: establish current property value
    if ($subject and $property) {
      $value = array();
      if ($datatype) {
        $datatype = $this
          ->processUri($node, $context, $datatype, true);
      }
      if ($content !== null) {
        $value['value'] = $content;
      }
      elseif ($node
        ->hasAttribute('datetime')) {
        $value['value'] = $node
          ->getAttribute('datetime');
        $datetime = true;
      }
      elseif ($datatype === '') {
        $value['value'] = $node->textContent;
      }
      elseif ($datatype === self::RDF_XML_LITERAL) {
        $value['value'] = '';
        foreach ($node->childNodes as $child) {
          $value['value'] .= $child
            ->C14N();
        }
      }
      elseif (is_null($datatype) and empty($rels) and empty($revs)) {
        $value['value'] = $this
          ->getUriAttribute($node, $context, array(
          'resource',
          'href',
          'src',
        ));
        if ($value['value']) {
          $value['type'] = 'uri';
        }
      }
      if (empty($value['value']) and $typedResource and !$node
        ->hasAttribute('about')) {
        $value['type'] = 'uri';
        $value['value'] = $typedResource;
      }
      if (empty($value['value'])) {
        $value['value'] = $node->textContent;
      }
      if (empty($value['type'])) {
        $value['type'] = 'literal';
        if ($datatype) {
          $value['datatype'] = $datatype;
        }
        elseif (isset($datetime) or $node->nodeName === 'time') {
          $value['datatype'] = $this
            ->guessTimeDatatype($value['value']);
        }
        if (empty($value['datatype']) and $lang) {
          $value['lang'] = $lang;
        }
      }

      // Add each of the properties
      foreach ($this
        ->processUriList($node, $context, $property) as $prop) {
        if ($node
          ->hasAttribute('inlist')) {
          $this
            ->addToList($listMapping, $prop, $value);
        }
        elseif ($subject) {
          $this
            ->addTriple($subject, $prop, $value);
        }
      }
    }

    // Step 12: Complete the incomplete triples from the evaluation context
    if (!$skip and $subject and ($context['incompleteRels'] or $context['incompleteRevs'])) {
      foreach ($context['incompleteRels'] as $prop) {
        $this
          ->addTriple($context['subject'], $prop, array(
          'type' => 'uri',
          'value' => $subject,
        ));
      }
      foreach ($context['incompleteRevs'] as $prop) {
        $this
          ->addTriple($subject, $prop, array(
          'type' => 'uri',
          'value' => $context['subject'],
        ));
      }
    }
  }

  // Step 13: create a new evaluation context and proceed recursively
  if ($node
    ->hasChildNodes()) {
    if ($skip) {
      $newContext = $context;
    }
    else {

      // Prepare a new evaluation context
      $newContext = $context;
      if ($object) {
        $newContext['object'] = $object;
      }
      elseif ($subject) {
        $newContext['object'] = $subject;
      }
      else {
        $newContext['object'] = $context['subject'];
      }
      if ($subject) {
        $newContext['subject'] = $subject;
      }
      $newContext['incompleteRels'] = $incompleteRels;
      $newContext['incompleteRevs'] = $incompleteRevs;
      if (isset($listMapping)) {
        $newContext['listMapping'] = $listMapping;
      }
    }

    // The language is always updated, even if skip is set
    $newContext['lang'] = $lang;
    foreach ($node->childNodes as $child) {
      if ($child->nodeType === XML_ELEMENT_NODE) {
        $this
          ->processNode($child, $newContext, $depth + 1);
      }
    }
  }

  // Step 14: create triples for lists
  if (!empty($listMapping)) {
    foreach ($listMapping as $prop => $list) {
      if ($context['listMapping'] !== $listMapping) {
        if ($this->debug) {
          print "Need to create triples for {$prop} => " . count($list) . " items\n";
        }
        $this
          ->generateList($subject, $prop, $list);
      }
    }
  }
}