Question

I have a requirement to make an XML file - and the partner is rather sticky about the header. Apparently, the header must be exactly this:

<?xml version="1.0"?>

But whenever I create an XML file I get extraneous properties like this:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

The hacker in me wants to stop using XMLWriter to make the file so that I have more control over the header; "no problem, I'll just write a loop that makes its own XML tags as a StreamWriter or something, forget this XMLWriter object..." but I must admit that XMLWriter has been rather elegant to use so far; surely there must be something where I can change the XMLWriterSettings object to say "stop putting your custom properties in to the XML header please", right?

Here's the relevant VB code:

    Dim settings As New XmlWriterSettings()
    settings.Indent = True
    settings.IndentChars = "    "
    settings.NewLineChars = "\n"
    Using writer As XmlWriter = XmlWriter.Create(strFileName, settings)
            writer.WriteStartDocument(True)
            For Each kvp As KeyValuePair(Of String, String) In dictArguments

                 Dim key As String = kvp.Key
                 Dim value As String = kvp.Value

                 writer.WriteStartElement(key)
                 writer.WriteString(value)
                 writer.WriteEndElement()

            Next

    End Using

Works perfectly; but I can't find a way to control the header. I can find a way to remove it entirely of course but that's not what we want to do.

Edit: thanks for the help; so far once we removed the WriteStartDocument it now no longer displays standalone = yes. I can't get it to stop adding the encoding however. Any ideas?

Was it helpful?

Solution

One way of doing this is to take control of the initial processing instruction yourself with the WriteProcessingInstruction method thus:

    Dim settings As New XmlWriterSettings()
    settings.Indent = True
    settings.IndentChars = "    "
    Using writer As XmlWriter = XmlWriter.Create(strFileName, settings)
        writer.WriteProcessingInstruction("xml", "version='1.0'")
        writer.WriteStartElement("root")
        For Each kvp As KeyValuePair(Of String, String) In dictArguments

            Dim key As String = kvp.Key
            Dim value As String = kvp.Value

            writer.WriteStartElement(key)
            writer.WriteString(value)
            writer.WriteEndElement()

        Next
        writer.WriteEndElement()

    End Using

Note that I've also added a "root" element in case your dictionary contains more than one element (and I'm guessing that none of the dictionary key values is "root" :)

OTHER TIPS

I know its been a few months since the question was asked, however I feel obliged to mention a (long-standing?) solution that I stumbled accross. It does do away with the entire xmldeclaration, and all you need to dois re-write just the declaration you need by writting a proccesing instruction.

XmlFragmentWriter - Omiting the Xml Declaration and the XSD and XSI namespaces

And here is the class in VB

Imports System.Xml
Imports System.IO
Imports System.Text

Class XmlFragmentWriter
Inherits XmlTextWriter

Public Sub New(ByVal w As TextWriter)
    MyBase.New(w)
End Sub

Public Sub New(ByVal w As Stream, ByVal encoding As Encoding)
    MyBase.New(w, encoding)
End Sub

Public Sub New(ByVal filename As String, ByVal encoding As Encoding)
    MyBase.New(New FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None), encoding)
End Sub


Private _skip As Boolean = False

Public Overrides Sub WriteStartAttribute(ByVal prefix As String, ByVal localName As String, ByVal ns As String)
    ' STEP 1 - Omits XSD and XSI declarations. 
    ' From Kzu - http://weblogs.asp.net/cazzu/archive/2004/01/23/62141.aspx
    If prefix = "xmlns" AndAlso (localName = "xsd" OrElse localName = "xsi") Then
        _skip = True
        Return
    End If
    MyBase.WriteStartAttribute(prefix, localName, ns)

End Sub

Public Overrides Sub WriteString(ByVal text As String)
    If _skip Then
        Return
    End If
    MyBase.WriteString(text)

End Sub

Public Overrides Sub WriteEndAttribute()
    If _skip Then
        ' Reset the flag, so we keep writing.
        _skip = False
        Return
    End If
    MyBase.WriteEndAttribute()

End Sub

Public Overrides Sub WriteStartDocument()
    ' STEP 2: Do nothing so we omit the xml declaration.
End Sub
End Class

and the usage here:

    Dim f As New XmlSerializer(GetType(OFXg))
      Dim w As New XmlFragmentWriter("c:\books1.xml", Nothing)
      w.Formatting = Formatting.Indented
      w.WriteProcessingInstruction("xml", "version=""1.0""")
      f.Serialize(w, RTofx)
      w.Close()

Of Course the OFXg class is an XMLSerializable

Why do you believe there are custom properties in the header?

WriteStartDocument writes the header with or without the standalone attribute. Your code adds the attribute you said your partner does not accept.

You did not show the code that used to produce the "utf-16", but I suspect it wrote to a StringWriter. Strings in .NET are always UNICODE, and you'll always get utf-16 when you write to a string. If you write to a stream, you get to control the encoding.

Necromancing.

You can create your own XmlTextWriter and override WriteStartDocument.

Example:

public class XmlTextWriterIndentedStandaloneNo : System.Xml.XmlTextWriter
{

    public bool bStandAlone = false;
    public bool bWriteStartDocument = true;
    public bool bOmitEncodingAndStandAlone = true;


    public XmlTextWriterIndentedStandaloneNo(System.IO.TextWriter w)
        : base(w)
    {
        Formatting = System.Xml.Formatting.Indented;
    } // End Constructor 


    public XmlTextWriterIndentedStandaloneNo(string strFileName, System.Text.Encoding teEncoding)
        : base(strFileName, teEncoding)
    {
        Formatting = System.Xml.Formatting.Indented;
    } // End Constructor 


    public XmlTextWriterIndentedStandaloneNo(System.IO.Stream w, System.Text.Encoding teEncoding)
        : base(w, teEncoding)
    {
        Formatting = System.Xml.Formatting.Indented;
    } // End Constructor 


    public override void WriteStartDocument(bool standalone)
    {
        if (bWriteStartDocument)
        {
            if (bOmitEncodingAndStandAlone)
            {
                this.WriteProcessingInstruction("xml", "version='1.0'");
                return;
            } // End if (bOmitEncodingAndStandAlone) 

            base.WriteStartDocument(bStandAlone);
        }

    } // End Sub WriteStartDocument 


    public override void WriteStartDocument()
    {
        // Suppress by ommitting WriteStartDocument
        if (bWriteStartDocument)
        {

            if (bOmitEncodingAndStandAlone)
            {
                this.WriteProcessingInstruction("xml", "version='1.0'");
                return;
            } // End if (bOmitEncodingAndStandAlone)

            base.WriteStartDocument(bStandAlone);
            // False: Standalone="no"
        } // End if (bWriteStartDocument)

    } // End Sub WriteStartDocument 


} // End Class XmlTextWriterIndentedStandaloneNo 

VB.NET

Public Class XmlTextWriterIndentedStandaloneNo
    Inherits System.Xml.XmlTextWriter

    Public bStandAlone As Boolean = False
    Public bWriteStartDocument As Boolean = True
    Public bOmitEncodingAndStandAlone As Boolean = True


    Public Sub New(w As System.IO.TextWriter)
        MyBase.New(w)
        Formatting = System.Xml.Formatting.Indented
    End Sub
    ' End Constructor 

    Public Sub New(strFileName As String, teEncoding As System.Text.Encoding)
        MyBase.New(strFileName, teEncoding)
        Formatting = System.Xml.Formatting.Indented
    End Sub
    ' End Constructor 

    Public Sub New(w As System.IO.Stream, teEncoding As System.Text.Encoding)
        MyBase.New(w, teEncoding)
        Formatting = System.Xml.Formatting.Indented
    End Sub
    ' End Constructor 

    Public Overrides Sub WriteStartDocument(standalone As Boolean)
        If bOmitEncodingAndStandAlone Then
            Me.WriteProcessingInstruction("xml", "version='1.0'")
            Return
        End If
        ' End if (bOmitEncodingAndStandAlone) 
        If bWriteStartDocument Then
            MyBase.WriteStartDocument(bStandAlone)
        End If
    End Sub
    ' End Sub WriteStartDocument 

    Public Overrides Sub WriteStartDocument()
        If bOmitEncodingAndStandAlone Then
            Me.WriteProcessingInstruction("xml", "version='1.0'")
            Return
        End If
        ' End if (bOmitEncodingAndStandAlone)
        ' Suppress by ommitting WriteStartDocument
        If bWriteStartDocument Then
                ' False: Standalone="no"
            MyBase.WriteStartDocument(bStandAlone)
        End If
        ' End if (bWriteStartDocument)
    End Sub
    ' End Sub WriteStartDocument 

End Class
' End Class XmlTextWriterIndentedStandaloneNo 

Usage example:

//using (System.Xml.XmlTextWriter wr = new System.Xml.XmlTextWriter(System.IO.Path.Combine(strBasePath, "TestFile.xml"), System.Text.Encoding.UTF8))
//using (System.Xml.XmlWriter wr = System.Xml.XmlWriter.Create(System.IO.Path.Combine(strBasePath, "TestFile.xml"), xwsSettings))
using (System.Xml.XmlWriter wr = new XmlTextWriterIndentedStandaloneNo(System.IO.Path.Combine(strBasePath, "TestFile.xml"), System.Text.Encoding.UTF8))
{
    //wr.Formatting = System.Xml.Formatting.None; // here's the trick !

    xdoc.Save(wr);
    wr.Flush();
    wr.Close();
} // End Using wr

This:

XmlWriterSettings xmlWriterSettings 
    = new XmlWriterSettings { OmitXmlDeclaration = true, };

will give you this:

<?xml version="1.0"?>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top