Omitting elements using custom XmlTextWriter - c#

I'm implementing a custom XmlTextWriter and I'd like to omit any elements with a particular name that contain no attributes. I've gotten as far as being able to prevent the element from being written by overriding WriteStartElement and WriteEndElement, but is there a way to know at WriteStartElement or at any other useful point whether or not the element has any attributes?

No. However you can postpone writing of the element and attributes (put them in a field) until you get to the next element/comment/etc. Then decide whether you want to write them or not.

Related

Does 'XmlDocument.CreateElement();' ONLY create an element?

It seems like someXml.CreateElement("abc"); does only one thing: create the element. It does not add it as a child as I expected, nor does it seem to do anything else.
But that doesn't make much sense. Why create an element with an instance method instead of with a static method? That would indicate that it does have some relationship to the instance. But I couldn't find anything and hence my question.
The remarks in Microsoft's Documentation mentions that default attributes are created on the returned object. Namespaces come to mind as they may be automatically applied to the new element based on the XmlDocument's schema/defaults.
It also states that it must be manually added to the desired parent node.
From https://msdn.microsoft.com/en-us/library/fw1ys7w6(v=vs.110).aspx
Note that the instance returned implements the XmlElement interface, so default attributes would be created directly on the returned object.
Although this method creates the new object in the context of the document, it does not automatically add the new object to the document tree. To add the new object, you must explicitly call one of the node insert methods.
I think the reason that the method doesn't automatically add the element as a child like you were expecting is because there would be no way to know where the element should be added. The document could have many children and there is nothing to specify which element the created element should be added to. It can't just add it by default to the root element, because there's a good chance that isn't always going to be the desired location.
As previously mentioned, the perks of having it be an instance method rather than a static method would be to automatically create the default attributes (such as namespace) on the newly created element. That way once it is created it should just need to be added to the proper location in the document.

XmlSerializer that treats null values as empty elements

I'm writing a small C# application that needs to be able to read/write some config data as XML. I'm doing this by creating some simple model classes with properties that have XmlElement attributes where needed, and running the whole thing through an XmlSerializer.
I would like to have the XmlSerializer behave exactly as it usually does, except I want any null properties on serialized objects to be written as empty elements. (Currently it skips them entirely.) And likewise, when deserializing, I'd like it to interpret empty elements as null, rather than as an empty string.
What's the most straight-forward way to achieve this? The suggestions I've seen for similar situations involve using the IsNullable argument for XmlElement, creating ShouldSerialize methods, etc. This has to be done for every property, creating a lot of unnecessary code. In this case, I want it to be universal for anything I'm (de)serializing. If I need to extend XmlSerializer, that's fine, and I could live with implementing IXmlSerializable on the model classes, but I'm not entirely sure where to start with those two possible approaches.

Is there a way to remove attribute after calling `AddAttribute`

Is there any way to remove attribute after the attribute was added by AddAttribute (msdn)?
Example:
public static void GenerateFieldInput(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.AddAttribute("placeholder", "some value");
// some code logic
writer.RemoveAttribute("placeholder"); // there isn't such method in HtmlTextWriter
}
HtmlTextWriter, like many other TextWriters, only writes stuff into a stream. There isn't an official way to delete stuff from it.
And why do you want to remove the attribute in the first place? Did you find that later on in the code, that the attribute is not needed anymore? If that's the case, try determining whether the tag is actually needed before you write it.
If you can't do that, you can put all the attributes you want to add in a List<T>, which allows you to add and delete elements. After you are absolutely sure that that is what you are going to write, do a foreach loop and write each attribute.

Using XmlWriter with more than 1 same attributes with diffrent values

I want to make an xml file (using c# with XmlWriter) and I need to have 2 or more Elements with different attribute Values. for example:
<MyGuest Type = "Adult" Number = "2">
<MyGuest Type = "Child" Number = "1" Age = "12">
is this something that can be done with XmlWriter? when I use
writer.WriteAttributeString("Number","2");
writer.WriteAttributeString("Type","Aduld");
writer.WriteAttributeString("Age","12");
writer.WriteAttributeString("Number","1");
writer.WriteAttributeString("Type","Child");
I get en exception that says "Additional information: 'Number' is a duplicate attribute name."
Any advice please?
So it seems that the question is asked wrongly. I want to add different values to that attributes in the xml file so it would look like this:
<Guests>
<MyGuest Type = "Adult" Number = "2">
<MyGuest Type = "Child" Number = "1" Age = "12">
</Guests>
any advice please?
Thank you for your time!
I think something like this is what you want:
writer.WriteStartElement("MyGuest");
writer.WriteAttributeString("Type","Adult");
writer.WriteAttributeString("Number","2");
writer.WriteEndElement();
writer.WriteStartElement("MyGuest");
writer.WriteAttributeString("Type","Child");
writer.WriteAttributeString("Age","12");
writer.WriteAttributeString("Number","2");
writer.WriteEndElement();
But generally it would be better to know more about your usecase. Are Child and Adult classes you want to serialize? Then I would propose you that the classes should implement IXmlSerializable. This forces the types to implement Read and WriteXml methods. In these methods you can put the logic and call them from outside. This gives you more loose coupling and also more flexibillity if you add new types. Then you dont have to change your "one-method-serialization" every time. You would only implement the new behaviour in the new class it belongs.
If you go this way, you could make also a abstract base class "Guest" that has the property "Number". In the base Read and WriteXml you would de/serialize just this property and you dont have to repeat yourself in every additional "guest type" like child or adult...
You can't do that: An attribute name cannot be used more than once in the same element.
Whatever way you use to accomplish your goal - the result is not valid XML.
Well-formed XML cannot contain duplicate attributes on an element.
From the xml spec section 3.1:
Well-formedness constraint: Unique Att Spec
An attribute name MUST NOT appear more than once in the same start-tag
or empty-element tag.
http://www.w3.org/TR/REC-xml/#sec-logical-struct

Custom XML Serialization, how to write custom root element?

I'm probably just doing this wrong, i know.
I'm using custom serialization and when the xml is generated it's putting the class name as the root element
Example:
<MyClassName>
<MyIntendedRootNode>
<ObjectType>
<Property1/>
<Property2/>
...
I'm invoking the serialization by calling xmlserializer.Serialize(writer,Me) so I'm sure that has something to do with it.
I've tried putting XMLRoot onto the class, but I think as vb is compiling this partial class with its aspx page, it's either overwriting this property or ignoring it entirely.
Ideally I'd like to just tell it to either throw away everything it has and use a different root element.
Anybody else do this except me?
Thanks
You can use either IXmlSerializable or use the XML attributes. I use XmlSerializer passing the root in the constructor.
var MemoryStream ms;
var customRoot = dataObject as XmlRootAttribute;
var xml = new XmlSerializer(dataObject.GetType(), customRoot);
xml.Serialize(ms, dataObject);
In ASP.NET, the actual class that is loaded is a generated class that inherits from your class. (It turns out--surprisingly--that this generated code is actually separate from the additional generated code that is combined with your code using the partial class technique. The generated class has the same name as the class you are working on, but it is in a different namespace.) Since XmlRoot is not an inherited attribute, the XmlSerializer does not see it.
I don't think there is any solution (other than modify the document after you have generated it).
Are you trying to serialize a codebehind file?
I would suggest writing a model to contain the data that needs to be saved, and then serializing that instead. Then use the appropriate XMLWriter attributes to make sure your root element is correctly named.
Or you could implement IXmlSerializable and have full control over your Xml but its a bit of extra effort just to change a root element name.
You can create a wrapper class and give that wrapper class with the name that you wish to be shown in the xml root.

Categories

Resources