| XML namespaces |
| ============== |
| |
| 1) requirements |
| --------------- |
| |
| GStreamer uses XML to save a complete media pipeline. This |
| opens a lot of possibilities for end user apps, eg: save |
| constructed pipelines for later reuse, send pipelines over |
| the wire to render data elsewhere etc... |
| |
| We will also allow the end user app to insert its own tags |
| into the GStreamer generated XML in order to give more |
| context to the elements. An example of such an app would be |
| gsteditor; while the GStreamer core will save the plain |
| element hierarchy, the editor will insert its own tags into |
| the XML tree to describe the elements positions, the |
| signals and other project data that might need to be |
| externalised. |
| |
| And inherent problem with XML is that the use and naming of |
| the tags can be done in an arbitrary way. The GStreamer core |
| will, for example, use the 'element' and 'pad' tags to store |
| the element and pad objects. The description and the nesting |
| of the tags are described in a DTD (document type definition) |
| or soon with the proposed 'new' standard of the W3C; Schemas. |
| |
| We can see obvious problems when a user app (unaware of the |
| core tags) is also trying to use the 'element' tag for its |
| own purposes. The core might try to load the 'element' tag |
| desscribing the user app data and the user app might get fed |
| with XML data of the GStreamer core. |
| |
| In this document we try to describe how we will solve this problem |
| using namespaces. |
| |
| |
| 2) namespaces |
| ------------- |
| |
| To avoid the tag conflicts we mentioned, the W3C has incorporated |
| XML namescapes. |
| |
| Were a typical XML document without namespaces would look like: |
| |
| <?xml version="1.0"?> |
| <GST-Pipeline> |
| <element> |
| <name>bin</name> |
| <children> |
| ... |
| </children> |
| </element> |
| </GST-Pipeline> |
| |
| Tha same document with namespaces look like this: |
| |
| <?xml version="1.0"?> |
| <gst:GST-Pipeline xmlns:gst="http://gstreamer.net/gst-core/1.0/"> |
| <gst:element> |
| <gst:name>bin</gst:name> |
| <gst:children> |
| ... |
| </gst:children> |
| </gst:element> |
| </gst:GST-Pipeline> |
| |
| In front of each tag we add, in this case, gst:. gst: is called the |
| namespace of the document and is declared with a statement: |
| |
| <... xmlns:gst="http://gstreamer.net/gst-core/1.0/"> |
| |
| In this case we define a new namespace 'gst:' that is tied to the URL |
| http://gstreamer.net/gst-core/1.0/. This URL is typically based on |
| a domain you control and doesn't have to point to something valid on |
| the internet. Note that the following document is exactly the same |
| as the one mentioned above: |
| |
| <?xml version="1.0"?> |
| <core:GST-Pipeline xmlns:core="http://gstreamer.net/gst-core/1.0/"> |
| <core:element> |
| <core:name>bin</gst:name> |
| <core:children> |
| ... |
| </core:children> |
| </core:element> |
| </core:GST-Pipeline> |
| |
| GStreamer currently uses xmlns:gst="http://gstreamer.net/gst-core/1.0" as |
| the namespace used for saving the core pipeline. |
| |
| 3) multi-namespace documents |
| ---------------------------- |
| |
| Suppose we have a user app that wants to insert its own XML tags into |
| the core GStreamer XML pipelines, for the examples sake we will use the |
| editor as an example. The editor will insert XML tags inside each |
| element that describes the position and size of the element as it was |
| laid out in the editor. |
| |
| For the examples sake, the tags that are used to descibe this meta data |
| will also be names 'element' in order to demonstrate the namespaces. |
| |
| The editor will use its own namespace, being: |
| xmlns:editor="http://gstreamer.net/gst-editor/1.0". This namespace is |
| added to the XML documents header and all the elements the editor will |
| save will have this namespace attached to it. Our interleaved XML |
| document might look like this: |
| |
| <?xml version="1.0"?> |
| <gst:GST-Pipeline xmlns:gst="http://gstreamer.net/gst-core/1.0/" |
| xmlns:editor="http://gstreamer.net/gst-editor/1.0/"> |
| <gst:element> |
| <gst:name>bin</gst:name> |
| <gst:children> |
| ... |
| </gst:children> |
| <editor:element> |
| <editor:position x="100" y="50"/> |
| </editor:element> |
| </gst:element> |
| </gst:GST-Pipeline> |
| |
| As you can see, the namespaces clearly separate the same XML tags |
| 'element'. |
| |
| |
| 4) implementation considerations |
| -------------------------------- |
| |
| The GStreamer core doesn't know about user apps inserting data into the |
| XML, it does not look at XML tags not within its namespace when it |
| performs the parsing of the XML tree. The core, however, must be |
| able to hand over the XML tree to the user app so it can perform the |
| parsing of its tags inside its namespace. We therefore need hooks inside |
| the framework to accomplish this. |
| |
| We also need hooks inside the GStreamer core to signal a user app that |
| it can now insert its tags into the XML tree. |
| |
| 4.1) XML save hooks |
| ------------------- |
| |
| GstObject has an abstract class method |
| |
| xmlNodePtr (*save_thyself) (GstObject *object, xmlNodePtr parent) |
| |
| A real element or pad will implement this function and construct an XML |
| representation of itself with the parent xmlNodePtr as the parent. |
| An element will typically call the save_thyself function of its |
| parent class before saving itself. |
| |
| The XML save procedure on a GstObject is performed with: |
| |
| gst_object_save_thyself (GstObject *object, xmlNodePtr parent) |
| |
| Wich will call the elements implementation of the save_thyself function. |
| |
| An app that wants to insert its XML tags has to connect to a signal of |
| the GstObject object called xml_saved. The object and the parent |
| xmlNodePtr will be passed to the signal handler of the user app, which |
| can then insert its tags. |
| |
| The user app has no problem inserting its namespace into the xmlDoc and |
| neither will the GStreamer core. |
| |
| 4.2) XML load hooks |
| ------------------- |
| |
| The real problem lies in the loading of the XML tree. Before we load |
| the objects, we don't have anything to connect a signal to, so |
| another method has to be invented to signal the user app of the |
| freshly loaded objects. |
| |
| One obvious solution would be to attach a class signal to the |
| GstObject class that would be fired whenever an object is created from |
| an XML document. Unfortunatly Gtk+ (or glib2.0) doesn't have class |
| signals so we need something else. Another problem with the class |
| signals would be that the user app would also be notified of object |
| creation outside its context. For example, if two threads perform an |
| XML load at the same time, the objects created in the first thread |
| would also notify the listener in the second thread. Both threads then |
| have to take care of not trying to parse XML documents that are from |
| the other thread, this obvously can get messy and we have to deal |
| with it without bothering the user app. |
| |
| We'll continue with some random ramblings... |
| |
| solution 1 |
| ---------- |
| To solve this problem we can create a special method in gstobject |
| |
| gst_object_loaded_notify_add (GstObjectLoadedCallback *callback, |
| xmlNodePtr doc) |
| |
| this method would add the specified callback function to a list of |
| listeners and would perform the callback function if an object is |
| created (this can be done in the init method). The problem remains |
| though because we do not know the xmlNodePtr when we call the |
| callback. This seems messy. |
| |
| sultion 2 |
| --------- |
| After the object has performed its restore_thyself, it is responsible |
| for signaling a object_loaded signal with the object and the xmlNodePtr |
| as an argument. |
| |
| At object creation, the signal is connected to a singleton object managed |
| by GstObject that can proxy the signal to the user app. This looks a |
| lot like a class signal. apps could also specify the xmlNodePtr they |
| are interested in and the signal would only be proxied to the app |
| if the xmlNodePtrs are from the same xmlDoc. |
| |
| Solution 2 seems like a reasonable solution for now... |
| |
| comments? |
| |
| wtay |
| |