2017-03-22 2 views
6

XML 파서가 요소가 비어 있거나 자동으로 닫히는 지에 대해 신경 쓰지 말아야한다는 사람들이 들리기 전에자가 폐쇄 형 XML 요소를 허용 할 수없는 이유가 있습니다. 그 이유는 내가 실제로 SGML이 XML이 아닌 SGML DTD로 작업한다는 것이 매우 엄격하고 그것을 허용하지 않기 때문입니다.C#에서 XmlDocument를 사용하여 빈 XML 요소를 자동으로 닫을 수 없도록하려면 어떻게해야합니까?

내가 가지고있는 것은 XSLT를 실행하는 데 필요한 수천 개의 SGML 파일입니다. 따라서 SGML을 XML로 임시 변환하여 XSLT를 적용해야했습니다. 그런 다음 다시 SGML로 변환하는 메소드를 작성했습니다. 기본적으로 XML 선언을 SGML 선언으로 대체하고 그래픽 엔티티와 같은 다른 엔티티 선언을 다시 작성합니다.

내 SGML 편집기로 파일을 열 때 SGML로 다시 변환 한 후 빈 요소가 자동 닫히기 때문에 파일을 구문 분석하지 못한다.

아무도 내가 XmlDocument 사용할 때 이런 일이 멈추지 않을 수 있습니다 어떻게 알 수 있습니까? 다시 XML로 SGML 변환하고

방법은 적절한 XmlWriter를 서브 클래스 화해, WriteFullEndElement() 전화를 WriteEndElement()을 무시하는 것입니다 할

//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); 
      } 


     } 

답변

2

한 가지 방법은 다음과 같습니다. 이 같은 사용해서

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(); 
    } 
} 

: 당신이 XmlWriterSettings에 의해 제공되는 제어를 필요로하는 경우,

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

을 또는 당신이 할 수있는,

예를 들어, 여기에 일을 XmlTextWriter의 서브 클래 싱 된 버전입니다 decorator 패턴을 사용하여 WriteEndElement()에서 WriteFullEndElement()으로 전화를 자동으로 다시 매핑하는 데코레이터에 XmlWriter을 캡슐화하십시오.

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); 
    } 
} 

비동기 쓰기를하고 있다면 비동기 메서드도 함께 꾸미고 싶다고 생각합니다.

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

우수하고 포괄적 인 답변입니다. 고맙습니다. 완전한. –

관련 문제