开发者

Save a DataSet ds.WriteXml(...) without <NewDataSet> Tag?

开发者 https://www.devze.com 2023-02-19 17:59 出处:网络
I can read and write a XML File into a Dataset with no problems, but if I save the DataSet with ds.WriteXml(\"Testdata.xml\")开发者_Go百科 a additional Tag <NewDataSet>.......</NewDataSet>

I can read and write a XML File into a Dataset with no problems, but if I save the DataSet with ds.WriteXml("Testdata.xml")开发者_Go百科 a additional Tag <NewDataSet>.......</NewDataSet> is generrated.

Is it possible to supress this Tag genaration?


A dataset can contain multiple tables and a valid XML file must contain a single root node that's why it is wrapped in this node. You could specify the name of the root node when creating the DataSet:

var ds = new DataSet("root");

but if you want to remove it you could first load the DataSet into a XDocument or XmlDocument and then extract the node you need and save it into a file.


I was looking to do the same thing in order to stream serialized DataRows without the overhead of tables and such. My solution was to use a temp DataTable as a sort of buffer which I fill with DataRows in chunks and then generate XML that I append to a stream. In order to reuse DataTable.WriteXml I had to solve the same problem and I wanted it to be efficient.

What I opted for is to create my own custom XmlWriter which is a lot simpler than it sounds. It works by skipping over elements that meet the condidtion of a predicate. In this case the predicate is whether the element name is the same as the expected DataSet name.

var writer = new RootlessDataSetXmlWriter(
    File.OpenWrite(@"C:\temp\ds.xml")
    "YourDataSetName");
dataSet.WriteXml(writer, XmlWriteMode.IgnoreSchema);
writer.Flush();
writer.Close();

Below is the implementation for RootlessDataSetXmlWriter and the ELementSkippingXmlWritter base class.

public class RootlessDataSetXmlWriter : ElementSkippingXmlWriter
{
    private string _dataSetName;

    public RootlessDataSetXmlWriter(Stream stream, string dataSetName)
        : base(stream, (e) => string.Equals(e, dataSetName, StringComparison.OrdinalIgnoreCase))
    {
        _dataSetName = dataSetName;
        this.Formatting = System.Xml.Formatting.Indented;
    }
}

public class ElementSkippingXmlWriter : XmlTextWriter
{
    private Predicate<string> _elementFilter;
    private int _currentElementDepth;
    private Stack<int> _sightedElementDepths;

    public ElementSkippingXmlWriter(Stream stream, Predicate<string> elementFilter)
        : base(stream, Encoding.UTF8)
    {
        _elementFilter = elementFilter;
        _sightedElementDepths = new Stack<int>();
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        if (_elementFilter(localName))
        {
            // Skip the root elements
            _sightedElementDepths.Push(_currentElementDepth);
        }
        else
        {
            base.WriteStartElement(prefix, localName, ns);
        }

        _currentElementDepth++;
    }

    public override void WriteEndElement()
    {
        _currentElementDepth--;

        if (_sightedElementDepths.Count > 0 && _sightedElementDepths.Peek() == _currentElementDepth)
        {
            _sightedElementDepths.Pop();
            return;
        }

        base.WriteEndElement();
    }
}


For those "efficient" like me, here are the simple XDocument and XmlDocument codez (live examples at https://dotnetfiddle.net/s2VP0k). Though XmlDocument was typically faster in my simple tests, I prefer the XDocument's simplicity.

XDocument:

return System.Xml.Linq.XElement
    .Parse(xmlString)
    .FirstNode
    .ToString(); // <c><a>123</a></c>

XmlDocument:

var xmlDoc = new System.Xml.XmlDocument();
xmlDoc.LoadXml(xmlString);
return xmlDoc.DocumentElement.InnerXml; // <c><a>123</a></c>
0

精彩评论

暂无评论...
验证码 换一张
取 消