Categories Displayed in Flash

Archive for the 'rdf' Category

AS3: Parsing XML with Nested Namespaces, SWF RDF metadata

Trying to parse the swf header to get at the metadata, which requires getting through nested namespaces in the RDF

The Flash Metadata embedded in the swf headers looks like:

<rdf:rdf xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:description xmlns:dc="http://purl.org/dc/1.1/">
<dc:title>A MetaData Example</dc:title>
<dc:description>This file has metadata embedded in it.</dc:description>
</rdf:description>
</rdf:rdf>

Namespaces are liked locked boxes, until you pass the key (e.g. setting default xml namespace = ns; or xml.ns::nodeName they are locked from opening anything beneath them, though it may appear otherwise when looking in the debugger.

So getting namespaces are required to parse the title and description. It would be easy to cheat and just hardcode the namespace, however it's bad form to hardcode the namespaces, as they change over different versions of the swf file format.

In addition the meta.namespaceDelcarations appears only to apply to the node it's associated with, meaning

  1.  
  2.    for (var i:uint = 0; i < meta.namespaceDeclarations().length; i++) {
  3.         var ns:Namespace = meta.namespaceDeclarations()[i];
  4.         trace(i + " ns " + ns.toString());
  5.         var prefix:String = ns.prefix;
  6.         if (prefix == "") {
  7.                 prefix = "(default)";
  8.         }
  9.         trace(prefix + ":" , ns.uri);
  10.  }

on the top level only returns the first name sapce of "http://www.w3.org/1999/02/22-rdf-syntax-ns#" when really we are after the dc namespace. But we need the first lock in order to open up the second.

Another approach is just parsing the string looking for the namespace prior to XML.

var rdfN:String = findXMLNS(nsr, 'xmlns:rdf="');
var dcN:String = findXMLNS(nsr, 'xmlns:dc="');
var rd:Namespace = new Namespace(rdfN);

  1.  
  2.   function findXMLNS(xmlS:String, nameSpace:String):String {
  3.      var a:Number = xmlS.indexOf(nameSpace);
  4.      var a2:Number = a + nameSpace.length;
  5.      var b:Number = xmlS.indexOf("\"", a2);
  6.      var res:String = xmlS.substring(a2,b);
  7.      return res;
  8.   }

Another warning is that namespaces var should be declared outside of a function if your else you'll get an error message of
VerifyError: Error #1025: An invalid register 13 was accessed.

Presumeably because namespaces as used by XML need to be scoped as non-temp local function scoped variables. So

  1.  
  2.  var dc:Namespace;
  3.  
  4.  function parseXML(Desc:XMLList){
  5.     //BAD! var ns = Desc.namespaceDeclarations()[0];
  6.     dc = Desc.namespaceDeclarations()[0]; //GOOD
  7.     //BAD         default xml namespace =  ns;
  8.     default xml namespace =  dc; //GOOD
  9.     trace("title:" + meta..title);
  10.  }