在我被人们说XML解析器不应该关心元素是空的还是自关闭的之前,我不能允许自关闭的XML元素是有原因的。原因是我实际上使用的是SGML,而不是XML,而且我正在使用的SGML DTD非常严格,不允许使用它。
我所拥有的是几千个SGML文件,我需要在这些文件上运行XSLT。因此,为了应用XSLT,我不得不暂时将SGML转换为XML。然后,我编写了一个将它们转换回SGML的方法(本质上只是将XML声明替换为SGML声明,并将任何其他实体声明(如图形实体)写回去)。
我的问题是,在转换回SGML之后,当我在SGML编辑器中打开文件时,文件不会解析,因为空元素已经自我关闭。
在使用XmlDocument时,有人知道我怎样才能阻止这种情况发生吗?
将SGML转换为XML并再次返回的方法如下所示
//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);
}
}发布于 2017-03-22 19:29:23
一种方法是对适当的XmlWriter进行子类化,并重写WriteEndElement()以调用WriteFullEndElement()。
例如,下面是执行此任务的XmlTextWriter的子类版本:
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();
}
}然后像这样使用它:
string xmltext;
using (var stringWriter = new StringWriter())
{
using (var xmlTextWriter = new FullElementXmlTextWriter(stringWriter))
{
myDoc.WriteTo(xmlTextWriter);
}
xmltext = stringWriter.ToString();
}或者,如果您需要XmlWriterSettings提供的控件,您可以使用装饰器模式将任何XmlWriter封装在一个装饰器中,该装饰器自动地将调用从WriteEndElement()映射到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);
}
}如果您正在进行异步编写,我相信(但还没有经过测试)您也希望装饰异步方法。
然后像这样使用它:
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();
}小提琴。
https://stackoverflow.com/questions/42959958
复制相似问题