Как добавить произвольное пространство имен в XslCompiledTransform во время выполнения? - PullRequest
1 голос
/ 25 октября 2011

Я пытаюсь выполнить очень простое преобразование документов языка разметки временного текста (TTML). Вот минималистский пример файла TTML:

<?xml version="1.0" encoding="UTF-8"?>
<tt xml:lang="en" xmlns="http://www.w3.org/2006/04/ttaf1"
    xmlns:tts="http://www.w3.org/2006/04/ttaf1#styling">
    <head>
    </head>
    <body>
        <div xml:lang="en" style="1">
            <p begin="00:00:00.20" dur="00:00:02.26">&gt;&gt; One time entry<br/>with a line break.</p>
        </div>
    </body>
</tt>

Обратите внимание на пространство имен документа по умолчанию. Это ключ к моей проблеме.

Вот преобразование, которое я использую. Это все, это очень просто.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    xmlns:tt="http://www.w3.org/2006/04/ttaf1">
    <xsl:output method="text" indent="yes" />
    <xsl:strip-space elements="*" />
    <xsl:preserve-space elements="tt:p"/>

    <!-- The indentation of the close tag for the following node is crucial to the transformed layout. Don't move it! -->
    <xsl:template match="tt:p"><xsl:apply-templates />&#160;
</xsl:template>

    <xsl:template match="tt:p/text()"><xsl:copy />&#160;</xsl:template>

</xsl:stylesheet>

Наш набор данных содержит сотни документов, и у них не все одинаковое пространство имен по умолчанию. Однако, как видно из приведенного выше XSLT, преобразование является простым и основано на базовом элементе данных <p />, поэтому в конечном итоге изменения пространства имен не важны.

Вышеупомянутый XSL в настоящее время работает с некоторыми из исходных файлов, поскольку файл XSLT имеет явно определенный префикс пространства имен (tt). Однако это не работает при обнаружении другого исходного файла с другим пространством имен по умолчанию.

Поэтому мне нужно найти способ предоставить XSLT произвольное неизвестное значение пространства имен для известного префикса. У меня есть код, который можно использовать для поиска пространства имен по умолчанию для исходного документа:

XPathDocument sourceDoc = new XPathDocument("sourcefile.xml");
XPathNavigator sourceNav = sourceDoc.CreateNavigator();
sourceNav.MoveToFollowing(XPathNodeType.Element);
var sourceNS = sourceNav.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml);
string defNS = sourceNS.Single(n => n.Key =="").Value;

Это правильно дает мне http://www.w3.org/2006/04/ttaf1. Тем не менее, я не могу понять, что делать с этим значением. Я искал и экспериментировал много часов, пытаясь каким-то образом предоставить экземпляру XslCompiledTransform пространство имен переменной. Похоже, что внутри области самого преобразования нет ничего, что могло бы его принять.

Я пытался явно загрузить XSLT-файл в XmlDocument, чтобы манипулировать таблицей имен (после удаления явного объявления xmlns:tt="..." пространства имен в приведенном выше XSLT):

XslCompiledTransform objXsl = new XslCompiledTransform();
StringWriter writer = new StringWriter();
XPathDocument sourceDoc;
XmlDocument xslDoc = new XmlDocument();
XPathNavigator sourceNav, xslNav;
XmlNamespaceManager xslNsManager;

sourceDoc = new XPathDocument("sourcefile.xml");
sourceNav = sourceDoc.CreateNavigator();
sourceNav.MoveToFollowing(XPathNodeType.Element);
var sourceNS = sourceNav.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml);

xslDoc.Load("transform.xslt");

xslNsManager = new XmlNamespaceManager(xslDoc.NameTable);
xslNsManager.AddNamespace("tt", sourceNS.Single(n => n.Key =="").Value);

xslNav = xslDoc.CreateNavigator();
objXsl.Load(xslNav);

objXsl.Transform(sourceNav, null, writer);

Это продолжается до фактического преобразования, где я получаю XslLoadException с указанием, что Prefix 'tt' is not defined.

На данный момент я в растерянности. Все, что я могу найти в поиске, описывает помещение пространства имен в документ XSLT (который у меня уже есть, и он отлично работает для одного значения пространства имен). Я не могу найти ничего в документации MSDN или где-либо еще, где объясняется, как добавить определения пространства имен в преобразование на лету.

У кого-нибудь есть идеи?

Ответы [ 2 ]

1 голос
/ 26 октября 2011

Коллега рекомендовал мне просто добавить / манипулировать пространством имен переменных в документе XSL.Моя попытка изменить таблицу имен шла в правильном направлении, но это не сработало.Вот то, что я придумал, основываясь на его предложении:

XslCompiledTransform xslXform = new XslCompiledTransform();
StringWriter writer = new StringWriter();
XmlDocument xslDoc = new XmlDocument();
XPathNavigator sourceNav;

sourceNav = new XPathDocument(sourceFile).CreateNavigator();
sourceNav.MoveToFollowing(XPathNodeType.Element);
var sourceNS = sourceNav.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml);
string ttNamespace = sourceNS.Single(n => n.Key == "").Value;

xslDoc.Load(xslFile);
xslDoc.DocumentElement.SetAttribute("xmlns:tt", ttNamespace);
xslXform.Load(xslDoc.CreateNavigator());
xslXform.Transform(sourceNav, null, writer);

Это работает, но мне кажется немного хакерским.Я думаю, что основная проблема заключается в том, что я не понимаю взаимосвязи между (Xml | XPath) Document типами и менеджером таблицы имен / пространства имен, связанным с ними.

0 голосов
/ 26 октября 2011

Я пробую это, эта работа.

using System;
using System.Xml.Xsl;

class Sample {
    static public void Main(){
        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load("transform.xslt");
        xslt.Transform("sourcefile.xml", "result.txt");
    }
}

Я думаю, что Пространство имен не проблема.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...