I’m developing a XML Validation service that uses multiple XML Schema files for validation of XML files in my application. XML Schema files use imports heavily. For that reason I need a service, that would associate namespaces to their schema definitions (file locations).
Each XML namespace is defined in separate XSD.
I know I could use schemaLocation attributes to connect schemas with their files, but that would require using lots of relative paths and wouldn’t work well with arbitrary project structures:
<-- schema.xsd -->
<xsd:import namespace="urn.my.namespace" schemaLocation="..."/>
<-- actual.xml -->
<root xmlns="urn.my.namespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn.my.namespace schema.xsd">
</root>
I would like to create a service that walks throughout bundles, discovers xsd files and registers their namespace – file location association into some kind of registry that would
be available for other XML services.
My Symfony project has the following structure:
AbcBundle/
Resources/config/services.xml
Resources/xsd/
schema.xsd
ns1.xsd
ns2.xsd
...
AbcBundle.php
XyzBundle/
[same structre]
Planned usage:
$nsLocator = $container->get('xml.ns_locator');
$nsLocator->getNamespaceMap();
/* returns array(
'urn:my:ns1' => '/realpath/to/ns1.xsd',
'urn:my:ns2' => '/otherpath/to/ns2.xsd',
*/
The $nsLocator should build that map automatically from Bundle/Resources/xsd/ directories.
I like the way that Symfony registers Bundle/Command or Bundle/Controller with its stack.
I was thinking of some kind of event listener that would hook into Kernel and once all Bundles are registered it would scan all XSDs and create a map. If done this way, It would require a caching so it doesn’t rescan all the files every time a new request or a command is executed.
How do I build that component and hook it into kernel? Where is the correct connection point for this component? Is it generally a good approach?
You should be able to create a compiler pass which would be run while the container is being built (after the main pass).
During your pass, get list of bundles and iterate through them to create a list of xsd files. Finally, pass the list to your service.
To get list of bundles:
Read more: