Created
July 10, 2015 12:59
-
-
Save stdray/a667c4ba97ff3f6d3d82 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Nemerle; | |
| using System; | |
| using System.Globalization; | |
| using System.Linq; | |
| using System.Xml.Linq; | |
| using Interfax.SM.ETL.Mapping.Macros.DSL; | |
| using Interfax.SM.ETL.Mapping.Types; | |
| using Interfax.SM.Utils; | |
| namespace Interfax.SM.ETL.Mapping.Goszakupki.Goszakupki44 | |
| { | |
| ///Модуль, который десериализует объекты в зависимости от версии схемы | |
| public module DispatchDeserializer | |
| { | |
| ///По версии схемы возвращает тип рутового элемента и соответствующий десериализатор | |
| Dispatch(version : string) : Type * IDeserializer | |
| { | |
| | "5.0" | "5.1" | "5.2" | null => | |
| ( typeof(Goszakupki44.Actual.Zakupki.Gov.Ru.Oos.Export.V1.export), | |
| Goszakupki44.Actual.Deserializer.Instance ) | |
| | "1.0" | "4.1" | "4.2" | "4.3" | "4.3.100" | "4.4" | "4.4.2" | "4.5" | "4.6" => | |
| ( typeof(Goszakupki44.Version_4_6.Zakupki.Gov.Ru.Oos.Export.V1.export), | |
| Goszakupki44.Version_4_6.Deserializer.Instance ) | |
| } | |
| //Десериализует рутовый объект документа в зависимости от версии схемы | |
| public RootObject(version : string, xml : XDocument) : object | |
| { | |
| def (rootType, _) = Dispatch(version); | |
| //очищаем и десериализуем | |
| Clean(version, xml).DeserializeFromXml(rootType) | |
| } | |
| //Десериализует объект документа в зависимости о версии схемы и типа документа | |
| public DocumentObject(version : string, documentType : string, xml : string) : object | |
| { | |
| def (_, deserializer) = Dispatch(version); | |
| deserializer.Deserialize(documentType, xml); | |
| } | |
| //Выполняет очистку документа от лишних тегов и исправляет известные ошибки в XML | |
| Clean(version : string, xml : XDocument) : XDocument | |
| { | |
| def praparedContent = XDocument.Load(xml.CreateReader()); | |
| //битые пространства имен, видимо какие-то криво сериализованные документ | |
| def fakeNamespaces = | |
| [ | |
| @"http://zakupki.gov.ru/oos/printform/1", | |
| @"http://zakupki.gov.ru/oos/integration/1" | |
| ]; | |
| //реализация очистки | |
| def clean(el) | |
| { | |
| def name = el.Name.LocalName; | |
| def parentName = el.Parent?.Name?.LocalName; | |
| def changes = System.Collections.Generic.List(); | |
| mutable nsChanged = false; | |
| //фиксим кривые префиксы неймспейсов | |
| foreach(attr in el.Attributes()) | |
| when(fakeNamespaces.Contains(attr.Value)) | |
| { | |
| changes.Add(() => | |
| { | |
| el.SetAttributeValue(attr.Name, @"http://zakupki.gov.ru/oos/types/1"); | |
| nsChanged = true; | |
| }); | |
| } | |
| //если простая чистка не помогла, пробуем перестроить тег | |
| when(!nsChanged && fakeNamespaces.Contains(el.Name.NamespaceName)) | |
| { | |
| def replaceTag() | |
| { | |
| def preparedElBoby = | |
| if(el.HasElements) //если есть дочерние элементы | |
| el.Elements() //то собираем их рекурсивно, применя очистку | |
| .Select(e => { def (_, r) = clean(e); r} ) | |
| .ToList() | |
| else | |
| el.Value : object; //иначе там какой-то текст | |
| def preparedEl = XElement(el.Name.LocalName, preparedElBoby); //новый элемент без неймспейса | |
| preparedEl.ReplaceAttributes(el.Attributes()); //добавляем ему атрибуты | |
| when(el.Parent != null) //если исходные элемент в дереве | |
| el.ReplaceWith(preparedEl); //заменяем его | |
| } | |
| changes.Add(replaceTag); | |
| } | |
| //чистим | |
| when( (String.IsNullOrWhiteSpace(el.Value) && !el.Attributes().Any()) //пустые теги (нет значения, нет атрибутов) | |
| || (name == "signature" && parentName == "printForm") //цифровую подпись печатной формы | |
| || name == "cryptoSigns" //цифровую подпись документа | |
| || name == "fcsClarification") //какую-то ненужность, которая много занимает | |
| { | |
| changes.Add(el.Remove); | |
| } | |
| //фиксим значения представленые в экспоненциальной форме (XmlSerializer не умеет с ними работать) | |
| when(name == "value" && parentName == "quantity") | |
| safe el.Value = decimal.Parse(el.Value, NumberStyles.Any).ToString(); | |
| //фиксим кривой уровень бюджета | |
| when(name == "budgetLevel" && parentName == "finances") | |
| { | |
| el.Value= | |
| if(el.Value.Length > 2) | |
| el.Value.Substring(0, 2); | |
| else if(version == "5.0" && el.Value[0] == '0') | |
| "1" + el.Value.Substring(1) | |
| else | |
| el.Value; | |
| } | |
| (changes, el); | |
| } | |
| try | |
| { | |
| def changes = praparedContent | |
| .Descendants() //идем по дереву элементов | |
| .Select(clean) //для каждого вызываем очистку | |
| .SelectMany((changes, _) => changes) //собираем их в единый список | |
| .Reverse() //инвертируем, потому что изменение элемента затрагивают его потом и последующие элементы | |
| .ToList(); | |
| //за один проход накатываем изменения | |
| foreach(change in changes) | |
| change(); | |
| praparedContent; | |
| } | |
| catch | |
| { | |
| | ex => | |
| System.Diagnostics.Trace.WriteLine(ex.Message); | |
| throw; | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment