Я хочу прочитать XML-файл, применить преобразование, а затем записать в другой файл. Наилучший способ, который я могу придумать, таков:
using (XmlTextReader reader = new XmlTextReader(new FileStream(_source, FileMode.Open)))
using (XmlTextWriter writer = new XmlTextWriter(new StreamWriter(_destination)))
{
_xslTransform.Transform(reader, writer);
}
Но я очень хочу добиться прогресса. Если я просто копирую данные, я могу сделать что-то вроде этого (это может быть не на 100% правильно, но что-то вроде этого):
using (BinaryReader reader = new BinaryReader(new FileStream(_source, FileMode.Open)))
using (BinaryWriter writer = new StreamWriter(_destination))
{
byte[] buffer = new byte[2048];
int read = 0;
int actual = 0;
long total = reader.BaseStream.Length;
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
{
writer.Write(buffer, 0, read);
actual = (actual <= total ? actual + read : read);
updateProgress(Convert.ToInt32(actual / total * 100));
}
}
Есть ли способ сделать это при использовании XslCompiledTransform. Я мог бы просто прочитать его в памяти перед записью в файл, но я хочу ограничить объем используемой памяти, или XslCompiledTransform все равно загружает все это в память?
Надеюсь, в этом есть какой-то смысл, спасибо!
Адам.





Можно отправить сообщения xsl: message из преобразования и прослушать эти сообщения.
При таком подходе вы должны сначала пройтись по входному документу и подсчитать узлы, которые ваше преобразование «повторяет». Это можно сделать с помощью очень простого XSLT, который просто отправляет сообщение на каждый интересующий узел.
Затем - во время фактического преобразования - каждый раз, когда вы попадаете в интересующий узел, вы можете отправить
<xsl:message terminate = "no">progress:mynode</xsl:message>
сообщение о ходе выполнения.
Это сообщение может быть перехвачено в вызывающем коде C# с помощью прослушивателя сообщений. Вы можете поместить следующий код в небольшой класс для применения преобразования XSL. Это просто базовый образец для иллюстрации; Надеюсь, вы поняли:
protected event MessageListener progressMessageIntercepted;
public void AddProgressMessageListener(MessageListener listener)
{
progressMessageIntercepted += listener;
}
public void RemoveMessageListeners()
{
progressMessageIntercepted = null;
}
protected void MessageCallBack(object sender, XsltMessageEncounteredEventArgs e)
{
if (e.Message.StartsWith("progress:"))
{
if (progressMessageIntercepted != null)
{
progressMessageIntercepted(this, null);
}
}
}
protected void Transform(string inputFile, string outputFile, string xsltFile)
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xsltFile);
XsltArgumentList parameters = new XsltArgumentList();
parameters.XsltMessageEncountered += new XsltMessageEncounteredEventHandler(MessageCallBack);
using (XmlWriter xmlWriter = XmlWriter.Create(outputFile))
{
xslt.Transform(inputFile, parameters, xmlWriter);
}
}
Не согласен. Вам не нужно добавлять логику кодирования в XSLT, вам нужно только добавить «трассирующие» сообщения в очень немногих местах, например начало одного матча-шаблона.
(продолжение) Как еще вы могли бы информировать клиента о прогрессе и о том, где вы находитесь в процессе преобразования, не вставляя дополнительную «логику» в свой XSLT?
Спасибо! Это решение отлично работает для меня. Теперь я знаю, что происходит внутри моих преобразований!
Я не собираюсь опускать его, потому что это умный ответ, и у меня нет лучшего ответа, но я должен сказать, что не уверен, что мне нравится помещать такую логику кодирования в файл xsl, который предназначен для описания как отформатировать / преобразовать XML-документ. Это нехорошее разделение забот.