private void ProcessAttributes(XmlReader reader, XmlWriter writer, string elementNS) { var attrs = new List <XmlAttributeInfo>(); var namespaces = new List <string>(); bool found; string prefix; reader.MoveToFirstAttribute(); do { if (reader.NamespaceURI == W3NAMESPACE.NAME) { if (reader.Value == elementNS) { // если это пространство имен элемента, то оно записывается отдельно первым - правило 7 continue; } else { // добавление для дальнейшей сортировки namespaces.Add(reader.Value); } } else { // добавление для дальнейшей сортировки attrs.Add(new XmlAttributeInfo(reader)); } }while (reader.MoveToNextAttribute()); attrs.Sort(); namespaces.Sort(); foreach (var ns in namespaces) { // объявление пространства имен только если оно используется - правило 4 if (attrs.Exists(a => a.NamespaceURI.Equals(ns))) { found = this.GetNamespacePrefix(ns, out prefix); if (!found) { // объявление пространства имен только если оно не было уже объявлено - правило 5 WriteNSAttribute(writer, ns, prefix); } } } foreach (var ai in attrs) { if (string.IsNullOrEmpty(ai.NamespaceURI)) { // запись unqualified атрибута writer.WriteStartAttribute(null, ai.LocalName, null); } else { // запись qualified атрибута с префиксом - он уже должен быть объявлен this.GetNamespacePrefix(ai.NamespaceURI, out prefix); writer.WriteStartAttribute(prefix, ai.LocalName, ai.NamespaceURI); } UnescapedGtWriter.WriteString(writer, ai.Value, this.UseOldEscaping, true); writer.WriteEndAttribute(); } reader.MoveToElement(); }
/// <summary> /// Главный метод преобразования /// </summary> private void DoSmevTransform() { if (this.innerDoc == null) { throw new InvalidOperationException("Not initalized"); } var settings = new XmlWriterSettings() { NewLineHandling = System.Xml.NewLineHandling.None, // по умолчанию - replace OmitXmlDeclaration = true, // правило 1 - удаление заголовка XML ConformanceLevel = System.Xml.ConformanceLevel.Fragment, Encoding = new UTF8Encoding(false) }; this.outputStream = new MemoryStream(); var writer = XmlWriter.Create(this.outputStream, settings); this.namespaceMapping.Clear(); this.nsCount = 0; this.currentLevel = 0; using (var reader = new XmlNodeReader(this.innerDoc)) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.XmlDeclaration: case XmlNodeType.Comment: case XmlNodeType.ProcessingInstruction: // правило 1 - удаление комментариев и инструкций break; case XmlNodeType.Element: this.CurrentLevel++; var elementNS = reader.NamespaceURI; if (!String.IsNullOrEmpty(elementNS)) { string prefix; // правило 6 - проверка префикса и генерация его в случае необходимости var found = this.GetNamespacePrefix(elementNS, out prefix); writer.WriteStartElement(prefix, reader.LocalName, elementNS); if (!found) { // правило 5 - объявление необъявленного пространства имен WriteNSAttribute(writer, elementNS, prefix); } } else { writer.WriteStartElement(reader.LocalName); } if (reader.HasAttributes) { // обработка правил 4,7 и 8 this.ProcessAttributes(reader, writer, elementNS); } // правило 3 - преобразование в пару start-tag + end-tag if (reader.IsEmptyElement) { writer.WriteFullEndElement(); this.CurrentLevel--; } break; case XmlNodeType.Text: // правило 2 - удаление значений из пробельных символов if (!string.IsNullOrEmpty(reader.Value.Trim())) { UnescapedGtWriter.WriteString(writer, reader.Value, this.UseOldEscaping, false); } break; case XmlNodeType.EndElement: writer.WriteFullEndElement(); this.CurrentLevel--; break; } } writer.Flush(); } }