#Copyright Massachusetts Institute of technology, 1999.
#Written by Eric Prud'hommeaux for the World Wide Web Consortium

# $Id: EmitterInterface.pm,v 1.89 2004/06/07 03:17:33 eric Exp $

#Workings decribed at http://www.w3.org/2002/12/26-XMLgrammer2RDFdb/
package W3C::Rdf::EmitterInterface;
use strict;

BEGIN {
    use Exporter;
    use vars qw($VERSION $DSLI @EXPORT @EXPORT_OK %EXPORT_TAGS);
    @EXPORT = qw ();
    @EXPORT_OK = qw( %States );
    %EXPORT_TAGS = ( STUFF => [ @EXPORT_OK, @EXPORT ] );
    $VERSION = 0.94;
    $DSLI = 'adpO';
}

use vars @EXPORT_OK;

sub import { goto &Exporter::import }

$W3C::Rdf::EmitterInterface::REVISION = '$Id: EmitterInterface.pm,v 1.89 2004/06/07 03:17:33 eric Exp $ ';


#####
# Externally available constants

*W3C::Rdf::EmitterInterface::PREDICATE_TYPE = \ 'type';
*W3C::Rdf::EmitterInterface::PREDICATE_TYPE_LI = \ 'li';
*W3C::Rdf::EmitterInterface::PREDICATE_PREDICATE = \ 'predicate';
*W3C::Rdf::EmitterInterface::PREDICATE_SUBJECT = \ 'subject';
*W3C::Rdf::EmitterInterface::PREDICATE_OBJECT = \ 'object';

*W3C::Rdf::EmitterInterface::OBJECT_ALT = \ 'Alt';
*W3C::Rdf::EmitterInterface::OBJECT_BAG = \ 'Bag';
*W3C::Rdf::EmitterInterface::OBJECT_SEQ = \ 'Seq';
*W3C::Rdf::EmitterInterface::OBJECT_STATEMENT = \ 'Statement';

*W3C::Rdf::EmitterInterface::ATTRIBUTION_REIFICATION = \ '<RDF reification>';
*W3C::Rdf::EmitterInterface::ATTRIBUTION_PROPERTY = \ '<RDF property>';

# hard-coded schema in a state-machine
%W3C::Rdf::EmitterInterface::Namespaces = 
('rdf:' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 
 'soap:' => "http://schemas.xmlsoap.org/wsdl/soap/", 
 'wsdlHttp:' => "http://schemas.xmlsoap.org/wsdl/http/", 
 'wsdl:' => "http://schemas.xmlsoap.org/wsdl/", 
 'xsd:' => "http://www.w3.org/2001/XMLSchema", 
 'p3p:' => "http://www.w3.org/2001/09/P3Pv1", 
 'dml:' => "http://www.daml.org/2001/03/daml+oil", 
 'disco:' => "http://schemas.xmlsoap.org/disco/", 
 'scl:' => "http://schemas.xmlsoap.org/disco/scl/", 
);

# Debugging technique:
#	printf debugging: echo("text", var) or error(var, "blah").
#	trace: add this to a command: trace="stack"

# Normalize with http://www.w3.org/2002/03/11-RDF-XSL$ xsltproc rdfToDB.xsl test.rdf 
# Beef up rdfToDB.xsl to have all state in stack and support parseType=Collection
# Write additional parser that dispatches xsltproc
# Invent axis for xsl:param

%W3C::Rdf::EmitterInterface::States = 
(
 # Outer production ignores elements until it hits a kind of element it knows about.
 'RDFWait' => {-common => {-start => 'nestState="RDFWait"', 
			   -char => '
charAct?error("description", characters, charAct)'}, 
	       -onTag => {'rdf:RDF' => {-start => 'nestState="RDFObject"; charAct="characters_not_allowed_in_RDF_element"'}, 
			  'rdf:ByPredicate' => {-start => 'nestState="ByPredicate"'}, 
			  'rdf:ByObjectID' => {-start => 'nestState="ByObjectId"'}, 
			  'rdf:ByType' => {-start => 'nestState="ByType"'}, 
			  'disco:discovery' => {-start => 'nestState="Disco"'}, 
			  'wsdl:definitions' => {-bind => {'wsdl:name' => 'defTNS#"definition_"defName', 
							   'wsdl:targetNamespace' => 'defTNS'}, 
						 -start => 'nestState="WSDLdef"; addStatement(\'rdf:type\', defName, \'wsdl:Description\', NULL)'}, #;defName=hashedUri(defName, defTNS)
			  'p3p:META' => {-bind => {'p3p:name' => 'p3pPolicyName', 'p3p:discuri' => 'p3pDiscuri'}, 
					 -start => 'nestState="p3pMeta"'}, 
			  'p3p:Policy' => {-bind => {'p3p:name' => 'p3pPolicyName', 'p3p:discuri' => 'p3pDiscuri'}, 
					   -start => '
nestState="p3pPolicy";
p3pDiscuri?addStatement(\'p3p:discuri\', p3pPolicyName, p3pDiscuri, NULL)'}}},

 # RDF striped syntax:
 # RDF typedNode --> http://www.w3.org/TR/1999/REC-rdf-syntax-19990222/#typedNode
 'RDFObject' => {-common => {-bind => {"rdf:ID" => '#object', "rdf:about" => 'object', "rdf:nodeID" => 'nodeID', 
				       "rdf:bagID" => '#reificationBag', "rdf:aboutEach" => 'aboutEach'}, 
			     -start => '
nestState="RDFProperty";
reifyChild[-2]?reificationBag=reifyChild[-2];
nodeID?object=getBNode(nodeID);
object?checkTrust(object);
predicate[-2]&&lastObject[-2]?error("description", object[-1], "already have", lastObject[-2],"object for property",predicate[-2]);
lastObject[-2]=object;
aboutEach?object=mappedNode(\'rdf:li\', aboutEach, NULL, reificationBag);
!aboutEach&&name!=\'rdf:Description\'?addStatement(\'rdf:type\', object[-1], name, NULL);
predicate[-2]&&!reifyChild[-2]&&object[-2]?error("description", object[-1], "inside a shortcut propertyElt", object[-2]);
predicate[-2]&&!reifyChild[-2]?addStatement(predicate[-2], object[-3], object[-1], reification[-2])', 
			     -attr => {
				 "rdf:resource" => ['reference', 
						    'error("resource", value, "inside a shortcut typedNode", object);'], 
				 "rdf:ID" => undef, "rdf:about" => undef, "rdf:nodeID" => undef, 
				 "rdf:bagID" => undef, "rdf:aboutEach" => undef}, 
			     -otherAttr => ['literal', 'addStatement(attribute, object[-1], value, GENID)'], 
			     -char => 'error("description", characters, "in typedNode", object)'}}, 

 # RDF propertyElt --> http://www.w3.org/TR/1999/REC-rdf-syntax-19990222/#propertyElt
 'RDFProperty' => {-common => {-bind => {"rdf:ID" => '#reification', "rdf:bagID" => '#reificationBag', "rdf:nodeID" => 'nodeID', 
					 "rdf:parseType" => '"parseType"', 'rdf:resource' => "object", 'rdf:datatype' => "datatype"}, 
			       -start => 'nestState="RDFObject";predicate=name;
nodeID?object=getBNode(nodeID);', 
			       -end => '
owlList?addStatement(\'rdf:rest\', owlList, \'rdf:nil\', reification[-1]);
owlList?addStatement(\'rdf:type\', \'rdf:nil\', \'rdf:List\', reification[-1]);
object[-1]?addStatement(predicate[-1], object[-2], object[-1], reification[-1])', 
			       -attr => {
				   "rdf:parseType" => ['literal', '
parseType=="Literal"?literalMode(addStatement, predicate[-1], object[-2], literal[-1], reification[-1]);
parseType=="Resource"?object=GENID;
parseType=="Resource"?nestState="RDFProperty";
parseType=="Collection"?owlList=GENID;
parseType=="Collection"?nestState="OWLList";
parseType=="Collection"?addStatement(predicate[-1], object[-2], owlList, reification[-1]);'], 
				   "rdf:ID" => undef, "rdf:bagID" => undef, "rdf:resource" => undef, "rdf:datatype" => undef, "rdf:nodeID" => undef},
			       -otherAttr => ['literal', 
					      'addStatement(attribute, object[-1], value, GENID)'], 
			       -char => '
lastObject?error("description", characters, "already have", lastObject,"object for property",predicate);
addStatement(predicate[-1], object[-2], characters, reification[-1])'}},

 # OWL
 # rdf:parseType="Collection"
 'OWLList' => {-common => {-bind => {"rdf:ID" => '#object', "rdf:about" => 'object', 
				       "rdf:bagID" => '#reificationBag', "rdf:aboutEach" => 'aboutEach'}, 
			     -start => '
nestState="RDFProperty";
reifyChild[-2]?reificationBag=reifyChild[-2];
object?checkTrust(object);
aboutEach?object=mappedNode(\'rdf:li\', aboutEach, NULL, reificationBag);
!aboutEach&&name!=\'rdf:Description\'?addStatement(\'rdf:type\', object[-1], name, NULL);
owlLast[-2]?owlList[-2]=GENID;
owlLast[-2]?addStatement(\'rdf:rest\', owlLast[-2], owlList[-2], reification[-2]);
owlLast[-2]=owlList[-2];
!reifyChild[-2]?addStatement(\'rdf:first\', owlList[-2], object[-1], reification[-2]);
!reifyChild[-2]?addStatement(\'rdf:type\', owlList[-2], \'rdf:List\', reification[-2])', 
			     -attr => {
				 "rdf:resource" => ['reference', 
						    'error("resource", value, "inside a shortcut typedNode", object);'], 
				 "rdf:ID" => undef, "rdf:about" => undef, "rdf:bagID" => undef, "rdf:aboutEach" => undef}, 
			     -otherAttr => ['literal', 'addStatement(attribute, object[-1], value, GENID)']}},

 # Eric Prud'hommeaux's experimental syntaxes:
 # ByPredicate or Colloquial XML --> http://www.w3.org/1999/03/31-XMLNamespace-values#Colloquial_XML
 'ByPredicate' => {-common => {-bind => {"rdf:predicate" => 'predicate', "rdf:subject" => 'subject', 
					 "rdf:object" => 'object', "rdf:literal" => '"object"', 
					 "rdf:reifiedId" => 'reifiedId', "rdf:reificationContainer" => 'reificationContainer'}, 
			       -start => 
		       '!predicate?predicate=name;nestState="ByPredicate";2?needStatement=1;
			-3&&reifyChild[-3]?reification=reifyChild[-3];
			reifyChild[-2]?needStatement=NULL;
			object?checkTrust(object);
		        needStatement[-2]?addStatement(predicate[-2], object[-3], object[-2], reification[-2]);
			needStatement[-2]?needStatement[-2]=NULL', 
			       -end => '
needStatement?addStatement(predicate[-1], object[-2], object[-1], reification[-1])', 
			       -attr => {"rdf:type" => ['reference', 'addStatement(\'rdf:type\', object[-1], value, NULL)'], 
					 "rdf:parseType" => ['literal', 'nestState=value', 
							     "rdf:reify" => 'reifyChild=GENID;reificationBag=reifyChild'], 
					 "rdf:predicate" => undef, "rdf:subject" => undef, "rdf:object" => undef, 
					 "rdf:literal" => undef, "rdf:reifiedId" => undef, "rdf:reificationContainer" => undef}, 
			       -otherAttr => ['literal', '
addStatement(attribute, object[-1], value, reification[-1])'], 
			       -char => 'addStatement(predicate[-1], object[-2], characters, reification[-1]);
needStatement=NULL'}, 
		   -onTag => {'rdf:RDF' => {-start => 'nestState="RDFObject";reifyChild=GENID;object=reifyChild'}, 
			      'rdf:ByPredicate' => {-start => 'nestState="ByPredicate"'}, 
			      'rdf:ByObjectID' => {-start => 'nestState="ByObjectId"'}, 
			      'rdf:ByType' => {-start => 'nestState="ByType"'}}}, 

 # Eric Prud'hommeaux's experimental syntaxes:
 # ByObjectID finds the node identifiers in the element names.
 'ByObjectID' => {-common => {-bind => {"rdf:predicate" => 'predicate', "rdf:subject" => 'subject', "rdf:object" => 'object', 
					"rdf:reifiedId" => 'reifiedId', "rdf:reificationContainer" => 'reificationContainer'}, 
			      -start => 
		               'nestState="ByObject";
				!object?object=name;
				!predicate?predicate="rdf:hasA";
				checkTrust(object);
				3?addStatement(predicate[-1], object[-2], object[-1], reification[-1])', 
			      -attr => {"rdf:type" => ['reference', 'addStatement(\'rdf:type\', object[-1], value, NULL)']}, 
			      -otherAttr => ['literal', '
addStatement(attribute, object[-1], value, reification[-1])']}}, 

 # Eric Prud'hommeaux's experimental syntaxes:
 # ByType finds the node types in the element names.
 'ByType' => {-common => {-bind => {"rdf:predicate" => 'predicate', "rdf:subject" => 'subject', "rdf:object" => 'object', 
				    "rdf:type" => 'type', "rdf:reifiedId" => 'reifiedId', 
				    "rdf:reificationContainer" => 'reificationContainer'}, 
			  -start => 
		  	       'nestState="ByType";
				!type?type=name;
				!predicate?predicate="rdf:hasA";
				object?checkTrust(object);
				3?addStatement(predicate[-1], object[-2], object[-1], reification[-1])', 
			  -otherAttr => ['literal', '
addStatement(attribute, object[-1], value, reification[-1])']}},

 # Parser for Disco files: ex http://www.xmethods.net/default.disco
 'Disco' => {-onTag => {'scl:contractRef' => {-bind => {'scl:ref' => 'ref', 'scl:docRef' => 'docRef'}, 
					      -start => 'addStatement(\'scl:contractDoc\', ref, docRef, NULL)'}}}, 

 # Parser for WSDL Definitions:
 'WSDLdef' => {-common => {-start => 'nestState="Error"', 
			   -char => 'error("CDATA ", characters, "in", nestState, "for tag", name)'}, 
	       -onTag => {'wsdl:types' => {-start => 'nestState="WSDLtypes"; typeBag=GENID'}, 
			  'wsdl:message' => {-bind => {'wsdl:name' => 'defTNS[-2]."#message("messageName', 
						       'xsd:name' => 'defTNS[-2]."#message("messageName'}, # !!! [ns1]
					     -start => 'nestState="WSDLmessage"', 
					     -attr => {"wsdl:name" => undef, "xsd:name" => undef}, 
					     -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)']}, 
						 # WSDL 1
			  'wsdl:portType' => {-bind => {'wsdl:name' => ['defTNS[-2]."#interface("portTypeName', 'defTNS[-2]."#operation("abstractName'], 
							'xsd:name' => 'defTNS[-2]."#interface("portTypeName'}, # !!! [ns1]
					      -start => 'nestState="WSDLpt";'}, 
						 # WSDL 2
			  'wsdl:interface' => {-bind => {'wsdl:name' => ['defTNS[-2]."#interface("portTypeName', 'defTNS[-2]."#operation("abstractName'], 
							'xsd:name' => 'defTNS[-2]."#interface("portTypeName'}, # !!! [ns1]
					      -start => 'nestState="WSDLpt";'}, 
			  'wsdl:binding' => {-bind => {'wsdl:name' => ['defTNS[-2]."binding_"bindingName', 'defTNS[-2]."#operation("abstractName999'], 
						       'xsd:name' => 'defTNS[-2]."binding_"bindingName', 
						       'wsdl:type' => [':"#interface("bindingType', ':"#operation("abstractName'], 
						       'xsd:type' => ':"#interface("bindingType'}, # !!! [ns1]
					     -start => '
nestState="WSDLbinding"; 
addStatement(\'wsdl:portType\', bindingName, bindingType, NULL)'},
			  'wsdl:service' => {-bind => {'wsdl:name' => 'defTNS[-2]."service_"serviceName', 
						       'xsd:name' => 'defTNS[-2]."service_"serviceName'}, # !!! [ns1]
					     -start => '
nestState="WSDLservice"; addStatement(\'wsdl:service\', defName[-2], serviceName, NULL);
addStatement(\'rdf:type\', serviceName, \'wsdl:Service\', NULL);'}}},

 # 
 'WSDLtypes' => {-onTag => {'xsd:schema' => {-bind => {'xsd:targetNamespace' => 'xsdtns'}, 
					     -start => 'nestState="XSDschema"'}}}, 

 # 
 'WSDLmessage' => {-common => {-start => 'nestState="Error"'}, 
		   -onTag => {'wsdl:part' =>{-bind => {"wsdl:name" => 'messageName[-2]."/"partId', 
						       "wsdl:element" => ':"xsd_"partElement',	# WSDL 1.1
						       "wsdl:type" => ':"xsd_"partElement'	# WSDL 1.2
						       }, 
					     -start => '
addStatement(\'wsdl:part\', messageName[-2], partId, NULL);
addStatement(\'wsdl:schemaRef\', partId, partElement, NULL);'}}}, 

 # 
 'WSDLpt' => {-common => {-start => 'nestState="Error"'}, 
#	      -onTag => {'wsdl:operation' => {-bind => {'wsdl:name' => ['abstractName[-2].opName', 'abstractNameTwo[-2].opNameTwo']}, 
	      -onTag => {'wsdl:operation' => {-bind => {'wsdl:name' => ['abstractName[-2].opName']}, 
					      -start => '
nestState="WSDLptOp";
addStatement(\'wsdl:abstractOperation\', portTypeName[-2], opName, NULL);
addStatement(\'rdf:type\', opName, \'wsdl:AbstractOperation\', NULL)'}}}, 

 # 
 'WSDLptOp' => {-common => {-bind => {'wsdl:message' => ':"#message("WSDLmessage'}}, 
		-onTag => {'wsdl:input' => {-start => 
						'addStatement(\'wsdl:abstractInput\', opName[-2], WSDLmessage, NULL)'},
			   'wsdl:output' => {-start => 
						 'addStatement(\'wsdl:abstractOutput\', opName[-2], WSDLmessage, NULL)'}, 
			   'wsdl:fault' => {-start => 
						'addStatement(\'wsdl:abstractFault\', opName[-2], WSDLmessage, NULL)'}}}, 

 # 
 'WSDLbinding' => {-common => {-start => 'nestState="Error"'}, 
		   -onTag => {'soap:binding' => {-bind => {'soap:style' => 'elementNs."styles_"soapStyle', 
							   'soap:transport' => 'soapTransport'}, 
						 -start => 'nestState="Error"; bindingId=GENID;
addStatement(\'soap:binding\', bindingName[-2], bindingId, NULL);
addStatement(\'soap:stype\', bindingId, soapStyle, NULL);
addStatement(\'soap:transport\', bindingId, soapTransport, NULL)'}, 
			      'wsdlHttp:binding' => {-bind => {'wsdlHttp:verb' => '"httpVerb"'}, 
						 -start => 'nestState="Error"; bindingId=GENID;
addStatement(\'wsdlHttp:binding\', bindingName[-2], bindingId, NULL);
addStatement(\'wsdlHttp:method\', bindingId, httpVerb, NULL)'}, 
			      'wsdl:operation' => {-bind => {'wsdl:name' => 'abstractName[-2].abstractOpName'}, 
						   -start => 'nestState="WSDLop";
boundOp=GENID;
addStatement(\'wsdl:boundOperation\', bindingName[-2], boundOp, NULL);
addStatement(\'rdf:type\', boundOp, \'wsdl:BoundOperation\', NULL);
addStatement(\'wsdl:abstraction\', boundOp, abstractOpName, NULL)'}}}, 

 # 
 'WSDLop' => {-onTag => {'soap:operation' => {-bind => {'soap:soapAction' => 'soapAction'}, 
					      -start => 'addStatement(\'soap:address\', boundOp[-2], soapAction, NULL)'}, 
			 'wsdl:input' => {-start => '
literalMode(addStatement, \'wsdl:boundInput\', boundOp[-2], literal, NULL);'}, 
			     'wsdl:output' => {-start => '
literalMode(addStatement, \'wsdl:boundOutput\', boundOp[-2], literal, NULL);'}, 
			     'wsdl:fault' => {-start => '
literalMode(addStatement, \'wsdl:boundFault\', boundOp[-2], literal, NULL);'}}}, 

 # 
 'WSDLservice' => {-common => {-start => 'nestState="Error"'}, 
		   -onTag => {'wsdl:documentation' => {-start => 'nestState="WSDLsrvcDoc"'}, 
			      'wsdl:port' => {-bind => {'wsdl:name' => 'defTNS[-3]."port_"portName', 
							'wsdl:binding' => ':"binding_"portBinding'}, 
					      -start => 'nestState="WSDLsrvcPort";
addStatement(\'wsdl:port\', serviceName[-2], portName, NULL);
addStatement(\'rdf:type\', portName, \'wsdl:Port\', NULL);
addStatement(\'wsdl:binding\', portName, portBinding, NULL);
addStatement(\'rdf:type\', portBinding, \'wsdl:PortBinding\', NULL)'}}}, 

 # 
 'WSDLsrvcDoc' => {-common => {-char => 'addStatement(\'wsdl:documentation\', serviceName[-3], characters, NULL)'}}, 

 # 
 'WSDLsrvcPort' => {-onTag => {'soap:address' => {-bind => {'soap:location' => 'soapAddress'}, 
						  -start => '
addStatement(\'soap:address\', portName[-2], soapAddress, NULL)'}}},

# XSD
 'XSDschema' => {-common => {-start => 'nestState="Error"'}, 
		 -onTag => {'xsd:element' => {-bind => {'xsd:name' => 'xsdtns[-2]."xsd_"XSDname'}, 
					      -start => '
literalMode(addStatement, \'wsdl:schemaDef\', XSDname, literal, NULL)'}}}, 

 # 
 'XSDelement' => {-common => {-start => '
literalMode(addStatement, \'wsdl:schemaDef\', XSDname[-2], literal, NULL);', 
				  -end => 'warn("XSD def created for ", XSDName[-2])'}}, 

 # P3P
 'p3pMeta' => {-common => {-start => 'nestState="Error"', 
			   -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			   -char => 'error("CDATA ", characters, "inside p3p:META.")'}, 
	       -onTag => {'p3p:POLICY-REFERENCES' => {-start => 'nestState="p3pPolRefs";
polRefSeq=GENID; addStatement(\'rdf:type\', polRefSeq, \'rdf:Seq\', NULL);
addStatement(\'rdf:type\', polRefSeq, \'p3p:PolicyRefs\', NULL)'}}},

 # 
 'p3pPolRefs' => {-common => {-bind => {'p3p:max-age' => '"max_age"', 'p3p:about' => 'polRefId'}, 
			      -start => 'nestState="Error"', 
			      -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			      -char => 'error("CDATA ", characters, "inside p3p:POLICY-REFERENCES.")'}, 
		  -onTag => {'p3p:EXPIRY' => {-start => '
expiry=GENID;
addStatement(\'p3p:expiry\', polRefSeq[-2], expiry, NULL);
addStatement(\'p3p:max-age\', expiry, max_age, NULL);'}, 
			  'p3p:POLICY-REF' => {-start => '
nestState="p3pPolicyRef"; addStatement(\'rdf:li\', polRefSeq[-2], polRefId, NULL)'}}},

 # 
 'p3pPolicyRef' => {-common => {-bind => {'p3p:cookieName' => '\"cookieName\"', 
					   'p3p:cookieValue' => '\"cookieValue\"', 
					   'p3p:cookieDomain' => '\"cookieDomain\"', 
					   'p3p:cookiePath' => '\"cookiePath\"'}, 
				-start => 'nestState="Error"', 
				-otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
				-char => 'addStatement(p, polRefId[-2], characters, NULL)'}, 
		    -onTag => {'p3p:INCLUDE' => {-start => 'nestState="p3pInclude";p=\'p3p:include\''}, 
			       'p3p:EXCLUDE' => {-start => 'nestState="p3pExclude";p=\'p3p:exclude\''}, 
			       'p3p:METHOD' => {-start => 'nestState="p3pInclud";p=\'p3p:method\''}, 
			       'p3p:includeCookies' => {-start => 'ic=GENID;
addStatement(\'p3p:includeCookies\', polRefId[-2], ic, NULL);
cookieName?addStatement(\'p3p:cookieName\', ic, cookieName, NULL);
cookieValue?addStatement(\'p3p:cookieValue\', ic, cookieValue, NULL);
cookieDomain?addStatement(\'p3p:cookieDomain\', ic, cookieDomain, NULL);
cookiePath?addStatement(\'p3p:cookiePath\', ic, cookiePath, NULL)'}}},

 # 
 'xp3pPolicyRef' => {-common => {-start => 'nestState="Error"', 
				 -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)']}, 
		    -onTag => {'p3p:INCLUDE' => {-start => 'nestState="p3pInclude"'}, 
			       'p3p:EXCLUDE' => {-start => 'nestState="p3pExclude"'}}, 
		    -char => 'error("CDATA ", characters, "inside p3p:POLICY-REF.")'},

 # 
 'p3pInclude' => {-common => {-start => 'nestState="Error"', 
			      -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			      -char => 'addStatement(\'p3p:include\', polRefId[-3], characters, NULL)'}},

 # 
 'p3pExclude' => {-common => {-start => 'nestState="Error"', 
			      -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			      -char => 'addStatement(\'p3p:exclude\', polRefId[-3], characters, NULL)'}},
 # more P3P
 'p3pPolicy' => {-common => {-start => 'nestState="Error"', 
			     -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			     -char => 'error("CDATA", characters, "inside", nestState, "for tag", name)'}, 
		 -onTag => {'p3p:ENTITY' => {-start => 'nestState="p3pEntity"'}}},

 # 
 'p3pEntity' => {-common => {-start => 'nestState="Error"', 
			     -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			     -char => 'error("CDATA", characters, "inside", nestState, "for tag", name)'}, 
		 -onTag => {'p3p:ENTITY' => {-start => 'nestState="p3pDataGroup"'}}},

 # 
 'p3pDataGroup' => {-common => {-start => 'nestState="Error"', 
				-otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
				-char => 'error("CDATA", characters, "inside", nestState, "for tag", name)'}, 
		    -onTag => {'p3p:ENTITY' => {-start => 'nestState="p3pData"'}}},

 # 
 'p3pData' => {-common => {-start => 'nestState="Error"', 
			   -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			   -char => 'error("CDATA", characters, "inside", nestState, "for tag", name)'}, 
	       -onTag => {'p3p:ENTITY' => {-start => 'nestState="p3pEntity"'}}},

 # 
 'p3pPolicy' => {-common => {-start => 'nestState="Error"', 
			     -attr => {'p3p:ref' => ['literal', '']}, 
			     # blowing off oddly opaque ref internals from http://www.w3.org/TR/P3P/base and elsewhere
			     -otherAttr => ['literal', '
error("attribute", attribute, "=", value, "in", nestState, "for tag", name)'], 
			     -char => 'error("CDATA", characters, "inside", nestState, "for tag", name)'}},

 # Error state. If you encounter elements here, you screwed up.
 'Error' => {-common => {-start => 'nestState="Error"'}}
 );

# [ns1] existing data may be in xsd or wsdl namespace.

# handy debugger idioms:
#use W3C::Rdf::EmitterInterface;
#use Data::Dumper;
#$States = \ %W3C::Rdf::EmitterInterface::States;
#print join ("\n", map {$state = $_; "$state: ".join (' | ', keys %{$States->{$state}})} keys %$States);

1;

__END__

=head1 NAME

W3C::Rdf::EmitterInterface - interface to fill an RDF database

=head1 SYNOPSIS

  use W3C::Rdf::EmitterInterface;

=head1 DESCRIPTION

Interface between an RDF emitter (for instance, W3C::Rdf::Parser) to
store RDF information in an RdfDB for later manipulation.

Actually, the really cool thing is that it (temporarily) holds the
parser state machine.

See L<http://www.w3.org/2002/12/26-XMLgrammer2RDFdb/> for details.

=head1 Parser State Machine

W3C::Rdf::Parser reads a set of syntax descriptors from a table and
uses them to parse the data passed from the XML parser.

=head2 actions

The core of the parser language is a simple command that takes n
actions sepparated by ';'s and performs the requested function calls
and assignments. The language is stilted, but it was designed to be
parsable with a single regular expression and easy to implement.

=head2 entry points

Unlike yak, SAX document handlers recieve input from a variety of
inputs. It is not sufficient to use a BNF grammer as a character
passed to startElement will be entirely different from a character
passed to ignorableWhitespace. Also, the data passed to the document
handler is already structured - attributes and values are passed in
via an AttibuteList.

Each state in the States structure represents a response to a
different document handler callback or provide a useful shortcut.

    names - a series of attribute name to variable name
    mappings. "rdf:predicate" => 'predicate' indicates that the value
    of the rdf:predicate attribute will be stored in the 'predicate'
    slot.

    startElementAction - actions to perform once the attributes that
    have names entries have been stored in the appropriate variable
    slot. see actions.

    attrActions - actions to perform when a certain attribute is
    encountered.

    foreignAttrActions - actions performed when there was no name
    mapping or attrActions for an attribute.

    characters - actions performed when the document handler
    characters method is called.

    endElementAction - actions performed when the document handler
    endElement method is called.

=head2 functions

The statemachine uses these functions:

    addStatement - call the RdfDB addStatement function.

    mappedNode - call the RdfDB mappedNode function.

    echo - dump the parameters to stdout. good for debugging.

    warning - call the error handler's warning function with a new
    SAXParserException

    error - call the error handler's error fucntion with a new
    SAXParserException

    fatalError - similar to the warning and error functions 
                 except that it is guaranteed to halt processing 
                 on this document.

=head2 variables

Some variables are declared and assigned when they are used as LVALUES
in actions or in a name mappings (see name). These variables may also
be assigned if used in a function call where a value is needed and a
genid is created if the variable is yet undefined.

Other variables are keywords maintained by the parser for programming
convience.

    nestState - the state that should be used if a startElement method
    is called.

    name - the name of the current tag

    attribute - contains the attribute name during calls to the
    attrActions and foreignAttrActions methods.

    value - contains the attribute value during calls to the
    attrActions and foreignAttrActions methods. assumed to be a
    string for foreignAttrActions calles.

=head2 bugz

W3C::Rdf::Parser assumes that all known attributes are mapped as URI
links and assigns the "value" variable accordingly. Those that must be
parsed as names (eg, they have an implicit leading '#') must be
handled in the named mappings. This is how 'parseType="Resource"' is
supported:

 'RDFProperty' => 
    {-names => {... "rdf:parseType" => '"parseType"'}, 
     ...
     -attrActions => {"rdf:parseType" => 
      ['literal', '...parseType=="Resource":nestState="RDFProperty"']...}},

This module is part of the W3C::Rdf CPAN module.

=head2 states

We enter a state either because we hit a known tag and must execute
the instructions associated with it, or because we are inside of an
element where any nested element implies some action. The former is
handled by element actions and element bindings. The latter and
handled by global actions and global bindings. The algorythm is:
 startElement
  add to state stack f(nestState)
  bind name to element name
  bind sp to stack pointer
  perform bindings from -names
  -startElementAction
  -onTag
  -attrActions|-foreignAttrActions

 endElement
  -endElementAction
  :or:
  bind literal
  dispatch pending funcs

 characters
  bind characters
  -characters

Variables Used:
  nestState - state to use to interpret nested elements
  name - name of an element
  sp - stack pointer
  attribute - attribute name
  value - attribute value
  characters - characters passed to the characters SAX handler

ParseState pieces:
  -literalMode
  -names
  -variables

moving to:
  element{$name}{-bindings => {}, 
                 -start => "", 
                 -end => "", 
                 -char => "",, 
                 -attrActions => {}, 
                 -foreighAttrActions {}}
  otherElements{-bindings => {}, 
                -start => "", 
                -end => "", 
                -char => "", 
                -attrActions => {}, 
                -foreighAttrActions {}}

=head1 AUTHOR

Eric Prud'hommeaux <eric@w3.org>

=head1 SEE ALSO

W3C::Rdf::RdfDB(3) W3C::Rdf::Parser(3) perl(1).

=cut
