Я пытаюсь выполнить очень простое преобразование документов языка разметки временного текста (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">>> 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 /> 
</xsl:template>
<xsl:template match="tt:p/text()"><xsl:copy /> </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 или где-либо еще, где объясняется, как добавить определения пространства имен в преобразование на лету.
У кого-нибудь есть идеи?