2017-03-22 17 views
6

Trước khi tôi bị mọi người nói rằng người phân tích cú pháp XML không nên quan tâm nếu các phần tử trống hoặc tự đóng, có một lý do tại sao tôi không thể cho phép các phần tử XML tự đóng. Lý do là tôi đang thực sự làm việc với SGML không phải XML và SGML DTD mà tôi đang làm việc rất nghiêm ngặt và không cho phép nó.Làm thế nào tôi có thể ngăn chặn các phần tử XML trống tự đóng bằng cách sử dụng XmlDocument trong C#?

Tôi có vài nghìn tệp SGML mà tôi cần để chạy XSLT. Do đó, tôi đã phải chuyển đổi SGML thành XML tạm thời để áp dụng XSLT. Sau đó tôi đã viết một phương thức chuyển đổi chúng trở lại SGML (về cơ bản chỉ thay thế khai báo XML bằng khai báo SGML và viết lại bất kỳ khai báo thực thể nào khác như các thực thể đồ họa).

Vấn đề của tôi là sau khi chuyển đổi này trở lại SGML, khi tôi mở tệp trong trình soạn thảo SGML của tôi, các tệp không phân tích cú pháp vì các phần tử trống đã tự đóng.

Có ai biết làm thế nào tôi có thể ngừng điều này xảy ra, vui lòng khi sử dụng XmlDocument?

Các phương pháp chuyển đổi các SGML to XML và ngược lại được trình bày dưới đây

//converts the SGML file to XML – it’s during this conversion that the 
//empty elements get self-closed, i think 

private XmlDocument convertToXML(TextReader reader) 
     { 
      // setup SgmlReader 
      Sgml.SgmlReader sgmlReader = new Sgml.SgmlReader(); 
      //sgmlReader.DocType = "HTML"; 
      sgmlReader.WhitespaceHandling = WhitespaceHandling.All; 
      sgmlReader.CaseFolding = Sgml.CaseFolding.ToLower; 
      sgmlReader.InputStream = reader; 


      // create document 
      XmlDocument doc = new XmlDocument(); 
      doc.PreserveWhitespace = true; 

      doc.XmlResolver = null; 
      doc.Load(sgmlReader); 
      return doc; 
     } 

// method to apply the XSLT stylesheet to the XML document 

private void filterApplic(string applicFilter) 
     { 
      string stylesheet = getRequiredStylesheet(); // do this just once 

      if (stylesheet != "") 
      { 
       foreach (string file in FilesToConvert) 
       { 
        fileName = Path.GetFileName(file); //gets just the file name from the path 
        fileNameNoExt = Path.GetFileNameWithoutExtension(file); 
        string ext = Path.GetExtension(file); 

        if (ext == ".sgm") 
        { 
         try 
         { 
          publicIdentifier = getDoctype(file); // gets the sgml declaration 
          entitiesList = getEntitites(file); // gets the list of entities 

          TextReader tr = new StreamReader(file); 
          myDoc = convertToXML(tr); 

          myDoc.Save(outputFolder + "\\temp.xml"); 

          var myXslTrans = new XslCompiledTransform(); 

          myXslTrans.Load(stylesheet); 
          myXslTrans.Transform(outputFolder + "\\temp.xml", Path.Combine(outputFolder, fileNameNoExt +".xml")); 

          XmlDocument convertedDoc = new XmlDocument(); 
          convertedDoc.Load(Path.Combine(outputFolder, fileNameNoExt + ".xml")); 

          convertToSGM(convertedDoc); 

          filesTransformed++; 
         } 
         catch (Exception e) 
         { 
          MessageBox.Show(e.ToString()); 
         } 

        } 
       } 
      } 
      else 
      { 
       MessageBox.Show("The stylesheet was retured empty. Cannot perform Applicability filter."); 
       return; 
      } 


      MessageBox.Show("Complete! " + filesTransformed.ToString() + " files filtered for " + applicFilter); 
     } 


//convert files back to SGML 
private void convertToSGM(XmlDocument myDoc) 
     { 

      using (var stringWriter = new StringWriter()) 
      using (var xmlTextWriter = XmlWriter.Create(stringWriter, settings)) 
      { 

       myDoc.WriteTo(xmlTextWriter); 
       xmlTextWriter.Flush(); 


       string xmltext = stringWriter.GetStringBuilder().ToString(); 

       xmltext = xmltext.Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", "<!DOCTYPE DMODULE " + publicIdentifier + ">"); 
       xmltext = xmltext.Replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "<!DOCTYPE DMODULE " + publicIdentifier + ">"); 

       if (entitiesList.Count != 0) 
       { 
        string entityListAsOne = ""; 

        foreach (string entity in entitiesList) 
        { 
         entityListAsOne = entityListAsOne + "\r\n" + entity; 
        } 

        xmltext = xmltext.Replace("//EN\">", "//EN\" [" + entityListAsOne + "]>"); 
       } 

       File.WriteAllText(Path.Combine(outputFolder, fileNameNoExt + ".sgm"), xmltext); 
      } 


     } 

Trả lời

2

Một cách để làm điều đó sẽ được phân lớp một thích hợp XmlWriter và ghi đè WriteEndElement() gọi WriteFullEndElement().

Ví dụ, đây là một phiên bản subclassed của XmlTextWriter mà không được công việc:

public class FullElementXmlTextWriter : XmlTextWriter 
{ 
    public FullElementXmlTextWriter(TextWriter w) : base(w) { } 

    public FullElementXmlTextWriter(Stream w, Encoding encoding) : base(w, encoding) { } 

    public FullElementXmlTextWriter(string filename, Encoding encoding) : base(filename, encoding) { } 

    public override void WriteEndElement() 
    { 
     base.WriteFullEndElement(); 
    } 
} 

Sau đó, sử dụng nó như:

string xmltext; 
using (var stringWriter = new StringWriter()) 
{ 
    using (var xmlTextWriter = new FullElementXmlTextWriter(stringWriter)) 
    { 
     myDoc.WriteTo(xmlTextWriter); 
    } 
    xmltext = stringWriter.ToString(); 
} 

Hoặc, nếu bạn cần sự kiểm soát dành bởi XmlWriterSettings, bạn có thể sử dụng mẫu trang trí để đóng gói bất kỳ XmlWriter nào trong trình trang trí tự động remaps cuộc gọi từ WriteEndElement() đến WriteFullEndElement():

public class FullElementXmlWriterDecorator : XmlWriterDecorator 
{ 
    public FullElementXmlWriterDecorator(XmlWriter baseWriter) : base(baseWriter) { } 

    public override void WriteEndElement() 
    { 
     base.WriteFullEndElement(); 
    } 
} 

public class XmlWriterDecorator : XmlWriter 
{ 
    readonly XmlWriter baseWriter; 

    public XmlWriterDecorator(XmlWriter baseWriter) 
    { 
     if (baseWriter == null) 
      throw new ArgumentNullException(); 
     this.baseWriter = baseWriter; 
    } 

    protected virtual bool IsSuspended { get { return false; } } 

    public override void Close() 
    { 
     baseWriter.Close(); 
    } 

    public override void Flush() 
    { 
     baseWriter.Flush(); 
    } 

    public override string LookupPrefix(string ns) 
    { 
     return baseWriter.LookupPrefix(ns); 
    } 

    public override void WriteBase64(byte[] buffer, int index, int count) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteBase64(buffer, index, count); 
    } 

    public override void WriteCData(string text) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteCData(text); 
    } 

    public override void WriteCharEntity(char ch) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteCharEntity(ch); 
    } 

    public override void WriteChars(char[] buffer, int index, int count) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteChars(buffer, index, count); 
    } 

    public override void WriteComment(string text) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteComment(text); 
    } 

    public override void WriteDocType(string name, string pubid, string sysid, string subset) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteDocType(name, pubid, sysid, subset); 
    } 

    public override void WriteEndAttribute() 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteEndAttribute(); 
    } 

    public override void WriteEndDocument() 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteEndDocument(); 
    } 

    public override void WriteEndElement() 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteEndElement(); 
    } 

    public override void WriteEntityRef(string name) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteEntityRef(name); 
    } 

    public override void WriteFullEndElement() 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteFullEndElement(); 
    } 

    public override void WriteProcessingInstruction(string name, string text) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteProcessingInstruction(name, text); 
    } 

    public override void WriteRaw(string data) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteRaw(data); 
    } 

    public override void WriteRaw(char[] buffer, int index, int count) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteRaw(buffer, index, count); 
    } 

    public override void WriteStartAttribute(string prefix, string localName, string ns) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteStartAttribute(prefix, localName, ns); 
    } 

    public override void WriteStartDocument(bool standalone) 
    { 
     baseWriter.WriteStartDocument(standalone); 
    } 

    public override void WriteStartDocument() 
    { 
     baseWriter.WriteStartDocument(); 
    } 

    public override void WriteStartElement(string prefix, string localName, string ns) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteStartElement(prefix, localName, ns); 
    } 

    public override WriteState WriteState 
    { 
     get { return baseWriter.WriteState; } 
    } 

    public override void WriteString(string text) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteString(text); 
    } 

    public override void WriteSurrogateCharEntity(char lowChar, char highChar) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteSurrogateCharEntity(lowChar, highChar); 
    } 

    public override void WriteWhitespace(string ws) 
    { 
     if (IsSuspended) 
      return; 
     baseWriter.WriteWhitespace(ws); 
    } 
} 

Nếu bạn đang viết không đồng bộ, tôi tin (nhưng chưa được thử nghiệm) mà bạn cũng muốn trang trí các phương pháp không đồng bộ.

Sau đó sử dụng nó như:

string xmltext; 
using (var stringWriter = new StringWriter()) 
{ 
    using (var innerXmlWriter = XmlWriter.Create(stringWriter, settings)) 
    using (var xmlTextWriter = new FullElementXmlWriterDecorator(innerXmlWriter)) 
    { 
     myDoc.WriteTo(xmlTextWriter); 
    } 
    xmltext = stringWriter.ToString(); 
} 

fiddle.

+0

Câu trả lời hoàn hảo và toàn diện. Cảm ơn nhiều. Hoàn hảo. –

Các vấn đề liên quan