Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VB.NET XMLWriter: How to change what's in the header?

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?

like image 564
Kyle Avatar asked Dec 18 '22 07:12

Kyle


2 Answers

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" :)

like image 50
Dan Blanchard Avatar answered Dec 21 '22 22:12

Dan Blanchard


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

like image 20
nepaluz Avatar answered Dec 21 '22 23:12

nepaluz