Как добавить произвольное пространство имен в XslCompiledTransform во время выполнения?
Я пытаюсь выполнить очень простое преобразование документов языка разметки временного текста (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 или где-либо еще, где объясняется, как добавить определения пространства имен в преобразование на лету.
У кого-нибудь есть идеи?
2 ответа
Коллега порекомендовал мне просто добавить / манипулировать пространством имен переменных в документе 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
типы и имя таблицы / менеджер пространства имен, связанный с ними.
Я стараюсь, эта работа.
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");
}
}
Я думаю, что Пространство имен не проблема.