C# 使用override void WriteEndElement()时如何使用XmlWriterSettings()?
我使用的是一个遗留应用程序,它不导入缩写的空xml元素。例如: 坏空:C# 使用override void WriteEndElement()时如何使用XmlWriterSettings()?,c#,xml,serialization,C#,Xml,Serialization,我使用的是一个遗留应用程序,它不导入缩写的空xml元素。例如: 坏空: <foo /> 和客户端代码: var x_settings = new XmlWriterSettings(); x_settings.NewLineChars = Environment.NewLine; x_settings.NewLineOnAttributes = true;
<foo />
和客户端代码:
var x_settings = new XmlWriterSettings();
x_settings.NewLineChars = Environment.NewLine;
x_settings.NewLineOnAttributes = true;
x_settings.NewLineHandling = NewLineHandling.Replace;
x_settings.CloseOutput = true;
x_settings.Indent = true;
x_settings.NewLineOnAttributes = true;
//var memOut = new MemoryStream();
var writer = new XmlTextWriterFull(outputFilename, Encoding.UTF8); //Or the encoding of your choice
var x_serial = new XmlSerializer(typeof(YOUR_OBJECT_TYPE));
x_serial.Serialize(writer, YOUR_OBJECT_INSTANCE);
writer.Close();
但是,如果仔细观察,客户机代码中永远不会使用XmlWriterSettings
。因此,xml输出的格式非常糟糕。我的问题是:如何调整上述代码以接受XmlWriterSettings
工厂创建方法和密封/内部/抽象类的使用使得实现重写变得困难
我将接受另一种解决方案,我不同意我的上述解决方案
- 解决方案
public class XmlTextWriterFull : XmlTextWriter
{
public XmlTextWriterFull(TextWriter sink) : base(sink)
{
Formatting = Formatting.Indented;
}
public override void WriteEndElement()
{
base.WriteFullEndElement();
}
}
步骤2:添加以下客户端代码。确保使用您正在使用的类和实例替换您的\u对象\u类型和\u对象\u实例:
TextWriter streamWriter = new StreamWriter(outputFilename);
var writer = new XmlTextWriterFull(streamWriter);
var x_serial = new XmlSerializer(typeof (YOUR_OBJECT_TYPE));
x_serial.Serialize(writer, YOUR_OBJECT_INSTANCE);
writer.Close();
上述解决方法将生成以下空xml元素格式:
<foo>
</foo>
此解决方案的问题在于它添加了换行符(请注意,元素位于单独的行上)。这对您来说可能是可以接受的,但会导致我的旧版应用程序出现问题。如何
从中获取可怕的XmlWrappingWriter
类(为了简洁起见,我省略了代码)
这样,我们可以创建一个子类,如下所示(非常类似于您原来的子类):
然后可以这样调用它(同样非常类似):
在我的例子中,一个以前被渲染为
<Foo>
</Foo>
可用于将XmlWriter设置应用于XmlWriter
。我无法让它像我所希望的那样工作(例如,缩进从未工作过),并且在反编译代码时,似乎并不是所有的设置都与这个特定的方法一起使用,因此我的调用代码只是在输出文件中传递(某种类型的流也可以工作)。另一个选项
public class XmlCustomTextWriter : XmlTextWriter
{
private TextWriter _tw = null;
public XmlCustomTextWriter(TextWriter sink)
: base(sink)
{
_tw = sink;
Formatting = Formatting.Indented;
Indentation = 0;
}
public void OutputElement(string name, string value)
{
WriteStartElement(name);
string nl = _tw.NewLine;
_tw.NewLine = "";
WriteString(value);
WriteFullEndElement();
_tw.NewLine = nl;
}
}
您在问题中给出的变通解决方案添加了额外的换行符(启用缩进时),因为我们告诉编写者将此元素视为具有子元素
下面是我如何修改您的解决方法来动态操作缩进,以避免那些额外的换行
public class XmlTextWriterFull : XmlTextWriter
{
public XmlTextWriterFull(TextWriter sink)
: base(sink)
{
Formatting = Formatting.Indented;
}
private bool inElement = false;
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(prefix, localName, ns);
// Remember that we're in the process of defining an element.
// As soon as a child element is closed, this flag won't be true anymore and we'll know to avoid messing with the indenting.
this.inElement = true;
}
public override void WriteEndElement()
{
if (!this.inElement)
{
// The element being closed has child elements, so we should just let the writer use it's default behavior.
base.WriteEndElement();
}
else
{
// It looks like the element doesn't have children, and we want to avoid emitting a self-closing tag.
// First, let's temporarily disable any indenting, then force the full closing element tag.
var prevFormat = this.Formatting;
this.Formatting = Formatting.None;
base.WriteFullEndElement();
this.Formatting = prevFormat;
this.inElement = false;
}
}
}
把这个留在这里,以防有人需要它;因为上面的答案没有一个能帮我解决这个问题,或者看起来有点过分了
FileStream fs = new FileStream("file.xml", FileMode.Create);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter w = XmlWriter.Create(fs, settings);
w.WriteStartDocument();
w.WriteStartElement("tag1");
w.WriteStartElement("tag2");
w.WriteAttributeString("attr1", "val1");
w.WriteAttributeString("attr2", "val2");
w.WriteFullEndElement();
w.WriteEndElement();
w.WriteEndDocument();
w.Flush();
fs.Close();
诀窍是设置XmlWriterSettings.Indent=true并将其添加到XmlWriter中
编辑:
或者,您也可以使用
w.Formatting = Formatting.Indented;
不要添加XmlWriterSettings。下面的代码片段强制在同一行上打印结束标记(很抱歉,对于vb版本,使用C#重写相同的标记应该很容易):
不知道它是否解决了这个特殊情况,但您可以使用XmlWriter.Create重载,该重载接受现有的writer和设置。您可以将自己的writer实现传递给该方法。据我所知,它允许您“向底层XmlWriter对象添加其他功能”,但我不知道这是否包括格式设置。我无法回答自己的问题。但我确实找到了一个可以接受的解决办法。我会把它贴在这里,希望能帮助别人;然而,我仍然希望我的问题得到解决。我的变通方法不使用我想要的XmlWriterSettings。更新:我的旧版应用程序不接受上述变通方法,因为完整标记插入了换行元素;因此,标记显示在单独的行上。我发布了一个悬赏,想看看我是否能吸引更多的注意力。这有点蹩脚,但你可以输出后处理你的输出,并用代码替换\s+/code>你有机会看看我的答案吗?我很有信心它会解决你的问题。
<Foo></Foo>
XmlWriter.Create(XmlWriter, XmlWriterSettings)
public class XmlCustomTextWriter : XmlTextWriter
{
private TextWriter _tw = null;
public XmlCustomTextWriter(TextWriter sink)
: base(sink)
{
_tw = sink;
Formatting = Formatting.Indented;
Indentation = 0;
}
public void OutputElement(string name, string value)
{
WriteStartElement(name);
string nl = _tw.NewLine;
_tw.NewLine = "";
WriteString(value);
WriteFullEndElement();
_tw.NewLine = nl;
}
}
public class XmlTextWriterFull : XmlTextWriter
{
public XmlTextWriterFull(TextWriter sink)
: base(sink)
{
Formatting = Formatting.Indented;
}
private bool inElement = false;
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(prefix, localName, ns);
// Remember that we're in the process of defining an element.
// As soon as a child element is closed, this flag won't be true anymore and we'll know to avoid messing with the indenting.
this.inElement = true;
}
public override void WriteEndElement()
{
if (!this.inElement)
{
// The element being closed has child elements, so we should just let the writer use it's default behavior.
base.WriteEndElement();
}
else
{
// It looks like the element doesn't have children, and we want to avoid emitting a self-closing tag.
// First, let's temporarily disable any indenting, then force the full closing element tag.
var prevFormat = this.Formatting;
this.Formatting = Formatting.None;
base.WriteFullEndElement();
this.Formatting = prevFormat;
this.inElement = false;
}
}
}
FileStream fs = new FileStream("file.xml", FileMode.Create);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter w = XmlWriter.Create(fs, settings);
w.WriteStartDocument();
w.WriteStartElement("tag1");
w.WriteStartElement("tag2");
w.WriteAttributeString("attr1", "val1");
w.WriteAttributeString("attr2", "val2");
w.WriteFullEndElement();
w.WriteEndElement();
w.WriteEndDocument();
w.Flush();
fs.Close();
w.Formatting = Formatting.Indented;
Imports System.Xml
Imports System.IO
Public Class CustomXmlTextWriter
Inherits XmlTextWriter
Public Sub New(ByRef baseWriter As TextWriter)
MyBase.New(baseWriter)
Formatting = Xml.Formatting.Indented
End Sub
Public Overrides Sub WriteEndElement()
If Not (Me.WriteState = Xml.WriteState.Element) Then
MyBase.WriteEndElement()
Else
Formatting = Xml.Formatting.None
MyBase.WriteFullEndElement()
Formatting = Xml.Formatting.Indented
End If
End Sub
End Class