VB.NET XMLWriter: Как изменить то, что в заголовке? - PullRequest
4 голосов
/ 22 июня 2009

У меня есть требование сделать файл XML - и партнер довольно пристально относится к заголовку. Видимо, заголовок должен быть именно таким:

<?xml version="1.0"?>

Но всякий раз, когда я создаю XML-файл, я получаю посторонние свойства, подобные этому:

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

Хакер во мне хочет прекратить использовать XMLWriter для создания файла, чтобы я мог лучше контролировать заголовок; «Нет проблем, я просто напишу цикл, который создает свои собственные XML-теги как StreamWriter или что-то в этом роде, забудем об этом объекте XMLWriter ...», но я должен признать, что XMLWriter до сих пор был довольно элегантен в использовании; несомненно, должно быть что-то, где я могу изменить объект XMLWriterSettings, чтобы он сказал: «Прекратите помещать свои пользовательские свойства в заголовок XML, пожалуйста», верно?

Вот соответствующий код VB:

    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

Работает отлично; но я не могу найти способ контролировать заголовок. Конечно, я могу найти способ полностью удалить его, но мы этого не хотим.

Редактировать: спасибо за помощь; до сих пор, когда мы удалили WriteStartDocument, теперь он больше не отображается как standalone = yes. Я не могу заставить это прекратить добавлять кодировку как бы то ни было. Есть идеи?

Ответы [ 5 ]

10 голосов
/ 22 июня 2009

Один из способов сделать это - самостоятельно взять на себя управление начальной инструкцией обработки с помощью метода WriteProcessingInstruction, таким образом:

    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

Обратите внимание, что я также добавил элемент "root" на случай, если ваш словарь содержит более одного элемента (и я предполагаю, что ни одно из значений ключа словаря не является "root":)

2 голосов
/ 06 октября 2010

Я знаю, что прошло несколько месяцев с тех пор, как был задан вопрос, однако я чувствую себя обязанным упомянуть (давнее?) Решение, с которым я столкнулся. Это избавляет от всей декларации xml, и все, что вам нужно сделать, переписать только то объявление, которое вам нужно, написав инструкцию по обработке.

XmlFragmentWriter - пропуск декларации Xml и пространств имен XSD и XSI

А вот класс в 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

и использование здесь:

    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()

Конечно, класс OFXg является XMLSerializable

1 голос
/ 22 июня 2009

Почему вы считаете, что в шапке есть пользовательские свойства?

WriteStartDocument записывает заголовок с отдельным атрибутом или без него. Ваш код добавляет атрибут, который, как вы сказали, ваш партнер не принимает.

Вы не показали код, который использовался для создания "utf-16", но я подозреваю, что он записал в StringWriter. Строки в .NET всегда UNICODE, и вы всегда получите utf-16, когда будете писать в строку. Если вы пишете в поток, вы можете контролировать кодировку.

0 голосов
/ 29 октября 2014

Necromancing.

Вы можете создать свой собственный XmlTextWriter и переопределить WriteStartDocument.

Пример:

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 

Пример использования:

//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
0 голосов
/ 17 февраля 2012

Это:

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

даст вам это:

<?xml version="1.0"?>
...