Instruct XmlWriterSettings to use self-closing tags

14,191

Solution 1

You dont need any special settings for that:

XmlWriter output = XmlWriter.Create(filepath);
 output.writeStartElement("element");
 output.writeAttributeString("a", "1");
 output.writeEndElement();

That will give you an output of <element a="1" /> (Just tested it in an application I am working on writing xml for)

Basically if you dont add any data before you write the end element it will just close it off for you.

I also have the following XmlWriterSettings it may be one of these if it isnt working by default:

XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.Indent = true;
wSettings.ConformanceLevel = ConformanceLevel.Fragment;
wSettings.OmitXmlDeclaration = true;
XmlWriter output = XmlWriter.Create(filePathXml, wSettings);

Solution 2

Processing XML from an external file, I wrote the following class to get rid of Non-Empty Closed Elements. My XML now has self closing tags.

using System.Linq;
using System.Xml.Linq;

namespace XmlBeautifier
{
    public class XmlBeautifier
    {
        public static string BeautifyXml(string outerXml)
        {
            var _elementOriginalXml = XElement.Parse(outerXml);
            var _beautifiedXml = CloneElement(_elementOriginalXml);
            return _beautifiedXml.ToString();
        }

        public static XElement CloneElement(XElement element)
        {
            // http://blogs.msdn.com/b/ericwhite/archive/2009/07/08/empty-elements-and-self-closing-tags.aspx
            return new XElement(element.Name,
                element.Attributes(),
                element.Nodes().Select(n =>
                {
                    XElement e = n as XElement;
                    if (e != null)
                        return CloneElement(e);
                    return n;
                })
            );
        }

    }
}
Share:
14,191
Istrebitel
Author by

Istrebitel

Updated on July 20, 2022

Comments

  • Istrebitel
    Istrebitel almost 2 years

    I'm using XmlWriterSettings to write Xml to file. I have elements with only attributes, no children. I want them to output as:

    <element a="1" /> 
    

    instead of

    <element a="1"></element>
    

    Can i do it with XmlWriterSettings?

    EDIT:

    Code is as follows:

    private void Mission_Save(string fileName)
        {
            StreamWriter streamWriter = new StreamWriter(fileName, false);
            streamWriter.Write(Mission_ToXml());
            streamWriter.Close();
            streamWriter.Dispose();
    
            _MissionFilePath = fileName;
        }
    
    private string Mission_ToXml()
        {
            XmlDocument xDoc;
            XmlElement root;
            XmlAttribute xAtt;
    
            xDoc = new XmlDocument();
    
            foreach (string item in _MissionCommentsBefore)
                xDoc.AppendChild(xDoc.CreateComment(item));
    
            root = xDoc.CreateElement("mission_data");
            xAtt = xDoc.CreateAttribute("version");
            xAtt.Value = "1.61";
            root.Attributes.Append(xAtt); 
            xDoc.AppendChild(root);
    
            //Out the xml's!
            foreach (TreeNode node in _FM_tve_Mission.Nodes)
                Mission_ToXml_private_RecursivelyOut(root, xDoc, node);
    
            foreach (string item in _MissionCommentsAfter)
                xDoc.AppendChild(xDoc.CreateComment(item));
    
    
            //Make this look good
            StringBuilder sb = new StringBuilder();
            XmlWriterSettings settings = new XmlWriterSettings();
    
            settings.Indent = true;
            settings.IndentChars = "  ";
            settings.NewLineChars = "\r\n";
            settings.NewLineHandling = NewLineHandling.Replace;
            settings.OmitXmlDeclaration = true;
            using (XmlWriter writer = XmlWriter.Create(sb, settings))
            {
                xDoc.Save(writer);
            }
    
            return sb.ToString();
        }
    
    private void Mission_ToXml_private_RecursivelyOut(XmlNode root, XmlDocument xDoc, TreeNode tNode)
        {
            root.AppendChild(((MissionNode)tNode.Tag).ToXml(xDoc));
            foreach (TreeNode node in tNode.Nodes)
                Mission_ToXml_private_RecursivelyOut(root, xDoc, node);
        }
    

    here _FM_tve_Mission is a TreeView control which has nodes, each of the nodes has a tag of class MissionNode, which has ToXml method that returns XmlNode containing this MissionNode converted to xml

  • Istrebitel
    Istrebitel about 12 years
    No no no, you dont understand. I have very complex XML, actually its a mission editor for a game that stores scenarios (set of scripts and events and stuff) in xml format, so its dynamically generated and i'd like to ust xmlwriter to output it by just doing XmlWriter.Write(myXml)
  • jzworkman
    jzworkman about 12 years
    XmlWriter only has a static Create method. You can't call XmlWriter.Write() because it doesnt exist. You have to write each node with the name and attributes individually. From the explanation you gave this is exactly what you want. You cant just magically pass data to the xmlwriter and expect output. You have to tell it what elements and attributes to output.
  • Istrebitel
    Istrebitel about 12 years
    Ah sorry i was wrong, its called Save not Write.... What i meant is to use object of type XmlDocument's method Save(passing XmlWriter object), i added code to the OP
  • jzworkman
    jzworkman about 12 years
    Ok my next question is then, why are you trying to use the XmlDocument like its an XmlWriter instead of just using the XmlWriter to create your document? You could write all of that code using the XmlWriter and you would not need to be doing all this appending and creating element and attribute objects in your code. The only way you are going to get self closing tags is to use the XmlWriter. Adding elements to an XmlDocument will always add them as full elements(like they are created)
  • Istrebitel
    Istrebitel about 12 years
    No particular reason. When i was looking for a method to output some complex structure to xml, i found this code snipplet and evolved it into what you saw now. It worked perfectly before (i have similar code to output something different and it does output xml with /> at the end of elements with attributes but no children.
  • Istrebitel
    Istrebitel about 12 years
    So yeah, another problem is: same code (well, code to generate XmlNodes is different, code to output XmlDocument via Writer is same) provides different results..
  • jzworkman
    jzworkman about 12 years
    You may need to modify the toXml for your treeNode. Otherwise its hard to say if it was working before without knowing what changed. In my experience, XmlWriter is a better tool for formatting the xml the way you want it.
  • Istrebitel
    Istrebitel about 12 years
    I found what the problem was. I was assigning InnerText of the XmlNode with "". This action apparently makes it "expand" into <></> form. Without assigning it, it still remains the same "" but it wont expand without children. Problem solved
  • Cole Tobin
    Cole Tobin over 9 years
  • jzworkman
    jzworkman over 9 years
    @ColeJohnson Yea that setting can be used now in .Net 4.5 When I answered this question that property didn't exist(.Net 4.0). But good addition to the framework that it does now.
  • user2864740
    user2864740 over 4 years
    XmlNode.Clone(deep_or_shallow) doesn't have the same effect .. manually REMOVING the text element might.