diff --git a/src/OneScript.StandardLibrary/Xml/XmlWriterImpl.cs b/src/OneScript.StandardLibrary/Xml/XmlWriterImpl.cs index 466cd7b16..abb1b3d48 100644 --- a/src/OneScript.StandardLibrary/Xml/XmlWriterImpl.cs +++ b/src/OneScript.StandardLibrary/Xml/XmlWriterImpl.cs @@ -25,9 +25,9 @@ public class XmlWriterImpl : AutoContext, IDisposable { private TextWriterWithSettings _internalTextWriter; private XmlTextWriter _writer; - private XmlWriterSettingsImpl _settings = (XmlWriterSettingsImpl)XmlWriterSettingsImpl.Constructor(); + private XmlWriterSettingsImpl _settings = XmlWriterSettingsImpl.Constructor(); private int _depth; - private Stack> _nsmap = new Stack>(); + private readonly Stack> _nsmap = new(); private StringBuilder _stringBuffer; private const string DEFAULT_INDENT_STRING = " "; @@ -51,6 +51,12 @@ private void ExitScope() --_depth; } + private void CheckIfOpen() + { + if (_writer == null) + throw NotOpenException(); + } + #region Properties [ContextProperty("Отступ","Indent")] @@ -77,8 +83,9 @@ public XmlWriterSettingsImpl Settings [ContextMethod("ЗаписатьАтрибут","WriteAttribute")] public void WriteAttribute(string localName, string valueOrNamespace, string value = null) - { - if(value == null) + { + CheckIfOpen(); + if (value == null) { _writer.WriteAttributeString(localName, valueOrNamespace); } @@ -91,30 +98,35 @@ public void WriteAttribute(string localName, string valueOrNamespace, string val [ContextMethod("ЗаписатьБезОбработки","WriteRaw")] public void WriteRaw(string data) { + CheckIfOpen(); _writer.WriteRaw(data); } [ContextMethod("ЗаписатьИнструкциюОбработки","WriteProcessingInstruction")] public void WriteProcessingInstruction(string name, string text) { + CheckIfOpen(); _writer.WriteProcessingInstruction(name, text); } [ContextMethod("ЗаписатьКомментарий","WriteComment")] public void WriteComment(string text) { + CheckIfOpen(); _writer.WriteComment(text); } [ContextMethod("ЗаписатьКонецАтрибута","WriteEndAttribute")] public void WriteEndAttribute() { + CheckIfOpen(); _writer.WriteEndAttribute(); } [ContextMethod("ЗаписатьКонецЭлемента","WriteEndElement")] public void WriteEndElement() { + CheckIfOpen(); _internalTextWriter.TrimEndSlashes = true; _writer.WriteEndElement(); _internalTextWriter.TrimEndSlashes = false; @@ -124,7 +136,8 @@ public void WriteEndElement() [ContextMethod("ЗаписатьНачалоАтрибута","WriteStartAttribute")] public void WriteStartAttribute(string name, string ns = null) { - if(ns == null) + CheckIfOpen(); + if (ns == null) { _writer.WriteStartAttribute(name); } @@ -138,6 +151,7 @@ public void WriteStartAttribute(string name, string ns = null) [ContextMethod("ЗаписатьНачалоЭлемента","WriteStartElement")] public void WriteStartElement(string name, string ns = null) { + CheckIfOpen(); if (ns == null) { _writer.WriteStartElement(name); @@ -152,18 +166,21 @@ public void WriteStartElement(string name, string ns = null) [ContextMethod("ЗаписатьОбъявлениеXML","WriteXMLDeclaration")] public void WriteXMLDeclaration() { + CheckIfOpen(); _writer.WriteStartDocument(); } [ContextMethod("ЗаписатьСекциюCDATA","WriteCDATASection")] public void WriteCDATASection(string data) { + CheckIfOpen(); _writer.WriteCData(data); } [ContextMethod("ЗаписатьСоответствиеПространстваИмен","WriteNamespaceMapping")] public void WriteNamespaceMapping(string prefix, string uri) { + CheckIfOpen(); _writer.WriteAttributeString("xmlns", prefix, null, uri); _nsmap.Peek()[prefix] = uri; } @@ -171,18 +188,21 @@ public void WriteNamespaceMapping(string prefix, string uri) [ContextMethod("ЗаписатьСсылкуНаСущность","WriteEntityReference")] public void WriteEntityReference(string name) { + CheckIfOpen(); _writer.WriteEntityRef(name); } [ContextMethod("ЗаписатьТекст","WriteText")] public void WriteText(string text) { + CheckIfOpen(); _writer.WriteString(text); } [ContextMethod("ЗаписатьТекущий","WriteCurrent")] public void WriteCurrent(XmlReaderImpl reader) { + CheckIfOpen(); var nodeType = reader.NodeType.UnderlyingValue; switch (nodeType) { @@ -225,7 +245,8 @@ public void WriteCurrent(XmlReaderImpl reader) case XmlNodeType.Document: case XmlNodeType.DocumentFragment: case XmlNodeType.Notation: - throw new RuntimeException(new Localization.BilingualString($"Копирование узла {nodeType} не поддерживается")); + throw CopyingNotSupportedException(nodeType); + default: break; } @@ -292,7 +313,8 @@ private static (string prefix, string localName) splitName(string nameOrLocalNam [ContextMethod("ЗаписатьТипДокумента","WriteDocumentType")] public void WriteDocumentType(string name, string varArg2, string varArg3 = null, string varArg4 = null) { - if(varArg4 != null) + CheckIfOpen(); + if (varArg4 != null) { _writer.WriteDocType(name, varArg2, varArg3, varArg4); } @@ -309,6 +331,7 @@ public void WriteDocumentType(string name, string varArg2, string varArg3 = null [ContextMethod("НайтиПрефикс","LookupPrefix")] public IValue LookupPrefix(string uri) { + CheckIfOpen(); string prefix = _writer.LookupPrefix(uri); if (prefix == null) return ValueFactory.Create(); @@ -318,26 +341,24 @@ public IValue LookupPrefix(string uri) [ContextMethod("Закрыть","Close")] public IValue Close() { - if(IsOpenForString()) + if (_writer==null) + return ValueFactory.Create(String.Empty); + + _writer.Flush(); + _writer.Close(); + Dispose(); + + if (IsOpenForString()) { - _writer.Flush(); - _writer.Close(); - - Dispose(); - var result = _stringBuffer.ToString(); _stringBuffer = null; + return ValueFactory.Create(result); } else { - _writer.Flush(); - _writer.Close(); - Dispose(); - - return ValueFactory.Create(); + return ValueFactory.Create(String.Empty); } - } private void ApplySettings(BslValue encodingOrSettings) @@ -477,9 +498,7 @@ protected override void Dispose(bool disposing) public void Dispose() { - if (_writer != null) - _writer.Close(); - + _writer?.Close(); _writer = null; } @@ -490,5 +509,19 @@ public static XmlWriterImpl Create() } public XmlWriter GetNativeWriter() => _writer; + + public static RuntimeException NotOpenException() + { + return new RuntimeException + ("Приемник данных XML не открыт", + "XML data target is not opened"); + } + public static RuntimeException CopyingNotSupportedException(XmlNodeType nodeType) + { + return new RuntimeException + ($"Копирование узла типа {nodeType} не поддерживается", + $"Copying a node of type {nodeType} is not supported"); + } + } } diff --git a/tests/xmlwrite.os b/tests/xmlwrite.os index 5b3e4665f..0d2c426f5 100644 --- a/tests/xmlwrite.os +++ b/tests/xmlwrite.os @@ -43,6 +43,9 @@ ВсеТесты.Добавить("ТестДолжен_ЗаписатьТекущий_ИнструкцииОбработки"); ВсеТесты.Добавить("ТестДолжен_ЗаписатьТекущий_ОбъявлениеИТипДокумента"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьЗакрытиеПустого"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьТипВозвратаЗакрыть_ИзФайла"); Возврат ВсеТесты; @@ -759,3 +762,21 @@ ЧтениеXML.Прочитать(); юТест.ПроверитьРавенство(ЧтениеXML.ТипУзла, ТипУзла, Сообщение); КонецПроцедуры + +Процедура ТестДолжен_ПроверитьЗакрытиеПустого() Экспорт + Запись = Новый ЗаписьXML; + Результат = Запись.Закрыть(); + + юТест.ПроверитьРавенство(ТипЗнч(Результат), Тип("Строка")); + юТест.ПроверитьРавенство(Результат, ""); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьТипВозвратаЗакрыть_ИзФайла() Экспорт + Запись = Новый ЗаписьXML; + ИмяФайла = юТест.ИмяВременногоФайла("xml"); + Запись.ОткрытьФайл(ИмяФайла); + Результат = Запись.Закрыть(); + + юТест.ПроверитьРавенство(ТипЗнч(Результат), Тип("Строка")); + юТест.ПроверитьРавенство(Результат, ""); +КонецПроцедуры