public function transform(ProjectDescriptor $project, Transformation $transformation)
    {
        $structure = $this->loadAst($this->getAstPath($transformation));

        $proc = $this->getXslProcessor($transformation);
        $proc->registerPHPFunctions();
        $this->registerDefaultVariables($transformation, $proc, $structure);
        $this->setProcessorParameters($transformation, $proc);

        $artifact = $this->getArtifactPath($transformation);

        $this->checkForSpacesInPath($artifact);

        // if a query is given, then apply a transformation to the artifact
        // location by replacing ($<var>} with the sluggified node-value of the
        // search result
        if ($transformation->getQuery() !== '') {
            $xpath = new \DOMXPath($structure);

            /** @var \DOMNodeList $qry */
            $qry = $xpath->query($transformation->getQuery());
            $count = $qry->length;
            foreach ($qry as $key => $element) {
                Dispatcher::getInstance()->dispatch(
                    'transformer.writer.xsl.pre',
                    PreXslWriterEvent::createInstance($this)->setElement($element)->setProgress(array($key+1, $count))
                );

                $proc->setParameter('', $element->nodeName, $element->nodeValue);
                $file_name = $transformation->getTransformer()->generateFilename(
                    $element->nodeValue
                );

                if (! $artifact) {
                    $url = $this->generateUrlForXmlElement($project, $element);
                    if ($url === false || $url[0] !== DIRECTORY_SEPARATOR) {
                        continue;
                    }

                    $filename = $transformation->getTransformer()->getTarget()
                        . str_replace('/', DIRECTORY_SEPARATOR, $url);
                } else {
                    $filename = str_replace('{$' . $element->nodeName . '}', $file_name, $artifact);
                }

                $relativeFileName = substr($filename, strlen($transformation->getTransformer()->getTarget()) + 1);
                $proc->setParameter('', 'root', str_repeat('../', substr_count($relativeFileName, '/')));

                $this->writeToFile($filename, $proc, $structure);
            }
        } else {
            if (substr($transformation->getArtifact(), 0, 1) == '$') {
                // not a file, it must become a variable!
                $variable_name = substr($transformation->getArtifact(), 1);
                $this->xsl_variables[$variable_name] = $proc->transformToXml($structure);
            } else {
                $relativeFileName = substr($artifact, strlen($transformation->getTransformer()->getTarget()) + 1);
                $proc->setParameter('', 'root', str_repeat('../', substr_count($relativeFileName, '/')));

                $this->writeToFile($artifact, $proc, $structure);
            }
        }
    }