I'm trying to cleans the Xml element with the attribut "nil=true" inside a document.
I come up with this algo but I don't like how it's look.
Do anyone know a linq version of this algo?
/// <summary>
/// Cleans the Xml element with the attribut "nil=true".
/// </summary>
/// <param name="value">The value.</param>
public static void CleanNil(this XElement value)
{
List<XElement> toDelete = new List<XElement>();
foreach (var element in value.DescendantsAndSelf())
{
if (element != null)
{
bool blnDeleteIt = false;
foreach (var attribut in element.Attributes())
{
if (attribut.Name.LocalName == "nil" && attribut.Value == "true")
{
blnDeleteIt = true;
}
}
if (blnDeleteIt)
{
toDelete.Add(element);
}
}
}
while (toDelete.Count > 0)
{
toDelete[0].Remove();
toDelete.RemoveAt(0);
}
}
What's the namespace of the nil attribute? Put that inside { } like this:
public static void CleanNil(this XElement value)
{
value.Descendants().Where(x=> (bool?)x.Attribute("{http://www.w3.org/2001/XMLSchema-instance}nil") == true).Remove();
}
This should work..
public static void CleanNil(this XElement value)
{
var todelete = value.DescendantsAndSelf().Where(x => (bool?) x.Attribute("nil") == true);
if(todelete.Any())
{
todelete.Remove();
}
}
The extension method:
public static class Extensions
{
public static void CleanNil(this XElement value)
{
value.DescendantsAndSelf().Where(x => x.Attribute("nil") != null && x.Attribute("nil").Value == "true").Remove();
}
}
Sample usage:
File.WriteAllText("test.xml", #"
<Root nil=""false"">
<a nil=""true""></a>
<b>2</b>
<c nil=""false"">
<d nil=""true""></d>
<e nil=""false"">4</e>
</c>
</Root>");
var root = XElement.Load("test.xml");
root.CleanNil();
Console.WriteLine(root);
output:
<Root nil="false">
<b>2</b>
<c nil="false">
<e nil="false">4</e>
</c>
</Root>
as you can see, nodes <a> and <d> where removed as expected. The only thing to note is that you cannot call this method on the <Root> node because the root node cannot be removed, and you will get this run-time error:
The parent is missing.
I change my way to solve that issue and avoid to create nil on my nullable type
I use the following
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer%28v=vs.90%29.aspx
public class OptionalOrder
{
// This field should not be serialized
// if it is uninitialized.
public string FirstOrder;
// Use the XmlIgnoreAttribute to ignore the
// special field named "FirstOrderSpecified".
[System.Xml.Serialization.XmlIgnoreAttribute]
public bool FirstOrderSpecified;
}
Related
I'm trying to get some values from an XML Document.
Here is the Xml Document that being generated from DevExpress
<?xml version="1.0" encoding="ISO-8859-1"?>
<XtraSerializer version="15.2.5.0">
<Items>
<Item1 SelectedStencils="" CanvasSizeMode="AutoSize" PageSize="40000,40000"
Theme="Office" ItemKind="DiagramRoot" Size="40000,40000">
<Children>
<Item1 ItemKind="DiagramShape" Size="100,75" Shape="BasicShapes.Rectangle"
Position="19500,19440"/>
<Item2 ItemKind="DiagramShape" Size="100,90" Shape="BasicShapes.Triangle"
Position="19540,19660"/>
<Item3 ItemKind="DiagramConnector" EndPoint="19590,19660"
BeginPoint="19550,19515" EndItem="1" BeginItem="0" Points="19550,19650
19590,19650" EndArrow="Filled90"/>
<Item4 ItemKind="DiagramShape" Size="100,75" Shape="BasicShapes.Rectangle"
Position="19940,19440"/>
<Item5 ItemKind="DiagramConnector" EndPoint="19940,19477.5"
BeginPoint="19600,19477.5" EndItem="3" BeginItem="0" Points=""
EndArrow="Filled90"/>
<Item6 ItemKind="DiagramConnector" EndPoint="19940,19477.5"
BeginPoint="19590,19660" EndItem="3" BeginItem="1" Points="19590,19525
19930,19525 19930,19478" EndArrow="Filled90"/>
</Children>
</Item1>
</Items>
</XtraSerializer>
I'm trying to get the values "BeginItem" & "EndItem" from the "DiagramConnector" part.I tried to get these values with the DevExpress API BeginItem -- EndItembut each time I try, the values are always Null even though when the data is saved, its not null in the XML Document.So I figured getting the values directly from the XML document would be the best/only way.
Here is how I'm trying to get the values from the xml document.keep in mind that there could be a million DiagramConnection Objects.
class Program
{
static readonly string FolderLocation = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\Diagram Samples";
static readonly string FileName = "d.xml";
static void Main(string[] args)
{
string FullPath = System.IO.Path.Combine(FolderLocation, FileName);
using (XmlDocumentCreator xmlDocument = new XmlDocumentCreator(FullPath))
{
string data = xmlDocument.ReadDocument.ToString();
if (data.Contains("BeginItem") && data.Contains("EndItem"))
{
string xpath = "Items/Item1SelectedStencils/Children";
var nodes = xmlDocument.XMLDocument.SelectNodes(xpath);
foreach (XmlNode childrenNode in nodes)
{
Console.Write(childrenNode.SelectSingleNode("//BeginItem").Value);
}
}
}
Console.ReadKey();
}
}
And Here is my XML Document class I created, I know its not correct for this project as SelectNodes requires an XmlDocument, its just for testing.
class XmlDocumentCreator : IDisposable
{
public XmlDocument XMLDocument { get; set; }
// <summary>
/// XmlDocument Creator
/// </summary>
/// <param name="xmlDocumentPath">xmlPath</param>
public XmlDocumentCreator(string xmlDocumentPath)
{
XMLDocument = new XmlDocument();
XMLDocument.Load(xmlDocumentPath);
}
/// <summary>
/// Returns An Xml Document
/// Which Can Then Be Read.
/// </summary>
/// <returns></returns>
public XElement ReadDocument
{
get
{
if (XMLDocument != null)
{
return XElement.Parse(XMLDocument.InnerXml);
}
throw new Exception("XML Document Object Was Not Created");
}
}
/// <summary>
/// Will Dispose The XML Document
/// And Also Call The Garbage Collector.
/// </summary>
public void Dispose()
{
if (XMLDocument != null)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.SuppressFinalize(this);
GC.Collect();
Console.WriteLine("XML Document Object Disposed");
}
}
}
In a perfect world, once I can get the values that are needed during the loop for each value on I could put them to an anonymous type and do with them whatever.
I'm trying to import an XML file of nodes into the same node structure in a TreeView using C#. I have found a lot of example that use a single node structure, but have had a lot of issues traversing the XML file and populating the TreeView with it. This is a sample of the XML file:
<?xml version="1.0"?>
<xmlRoot>
<ProductGroup>
<Group>
<GroupName>Soda</GroupName>
<Classifications>
<Classification>
<ClassificationName>Regular</ClassificationName>
<Containers>
<Container>
<ContainerType>Can</ContainerType>
<ContainerName>SmallCan</ContainerName>
</Container>
<Container>
<ContainerType>bottle</ContainerType>
<ContainerName>SmallBottle</ContainerName>
</Container>
</Containers>
</Classification>
<Classification>
<ClassificationName>Diet</ClassificationName>
<Containers>
<Container>
<ContainerType>Can</ContainerType>
<ContainerName>SmallCan</ContainerName>
</Container>
</Containers>
</Classification>
</Classifications>
</Group>
<Group>
<GroupName>Water</GroupName>
<Classifications>
<Classification>
<ClassificationName>Regular</ClassificationName>
<Containers>
<Container>
<ContainerType>Bottle</ContainerType>
<ContainerName>EcoBottle</ContainerName>
</Container>
</Containers>
</Classification>
</Classifications>
</Group>
</ProductGroup>
</xmlRoot>
I've tried using something like this:
treProducts.Nodes.Clear();
XDocument xdoc = XDocument.Load("ProductDocument.xml");
foreach (XElement groupElement in xdoc.Descendants("Group"))
{
treProducts.Nodes.Add(groupElement.Element("GroupName").Value);
treProducts.SelectedNode = treProducts.Nodes[groupElement.Element("GroupName").Value];
foreach (XElement ClassificationElement in groupElement.Descendants("Classification"))
{
treProducts.SelectedNode.Nodes.Add(groupElement.Element("ClassificationName").Value);
treProducts.SelectedNode = treProducts.Nodes[groupElement.Element("ClassificationName").Value];
foreach (XElement ContainerElement in groupElement.Descendants("Container"))
{
treProducts.SelectedNode.Nodes.Add(ContainerElement.Element("ContainerName").Value);
}
}
}
I'm trying to get the tree to show:
Soda
Regular
SmallCan
SmallBottle
Diet
SmallCan
Water
Regular
EcoBottle
...but the tree is only showing Soda and it seems to skip the rest, except if I comment out the nested foreach statements, it will show Soda and Water.
There's something wrong with the syntax I'm using and I'm wondering if someone who understands Linq better can help see where the code is wrong.
You are using the wrong variable in your loop over the Classification Elements. Replace groupElement with ClassificationElement inside the loop.
Change:
foreach (XElement ClassificationElement in groupElement.Descendants("Classification"))
{
// groupElement.Element("ClassificationName") is null:
treProducts.SelectedNode.Nodes.Add(groupElement.Element("ClassificationName").Value);
...
}
to
foreach (XElement ClassificationElement in groupElement.Descendants("Classification"))
{
treProducts.SelectedNode.Nodes.Add(ClassificationElement.Element("ClassificationName").Value);
...
}
I suggest recursion
void AddNodes(XElement parentElement, TreeNode parent = null)
{
Queue<XElement> queue = new Queue<XElement>(parentElement.Elements());
while (queue.Count > 0)
{
TreeNode child = parent;
XElement element = queue.Dequeue();
if (!element.HasElements)
{
string value = element.Value;
element = (XElement)element.NextNode;
if (null != element && !element.HasElements)
value = element.Value;
if (null == parent)
treeView1.Nodes.Add(child = new TreeNode(value));
else
parent.Nodes.Add(child = new TreeNode(value));
child.Expand();
element = queue.Dequeue();
}
AddNodes(element, child);
}
}
AddNodes(XElement.Load("ProductDocument.xml"));
Note: dbc's answer is probably better if your XML structure is likely to change, but if you are given it as it currently stands, and it won't change - then this will slurp it right into the tree quickly, without a lot of overhead.
The reason this is complicated is that your tree node hierarchy does not correspond 1-1 to your XML hierarchy. In situations like this, I suggest introducing intermediate classes to provide a view into the base XML model data. In WPF these classes would be the View Model, but the windows forms TreeView doesn't support data binding. Despite this, the abstraction of a view model is useful here.
First, some basic view model interfaces and classes to tie together TreeNode and XElement hierarchies:
public interface ITreeNodeViewModel
{
string Name { get; }
string Text { get; }
object Tag { get; }
object Model { get; }
IEnumerable<ITreeNodeViewModel> Children { get; }
}
public abstract class TreeNodeViewModel<T> : ITreeNodeViewModel
{
readonly T model;
public TreeNodeViewModel(T model)
{
this.model = model;
}
public T Model { get { return model; } }
#region ITreeNodeProxy Members
public abstract string Name { get; }
public abstract string Text { get; }
public virtual object Tag { get { return this; } }
public abstract IEnumerable<ITreeNodeViewModel> Children { get; }
#endregion
#region ITreeNodeViewModel Members
object ITreeNodeViewModel.Model
{
get { return Model; }
}
#endregion
}
public abstract class XElementTreeNodeViewModel : TreeNodeViewModel<XElement>
{
public XElementTreeNodeViewModel(XElement node) : base(node) {
if (node == null)
throw new ArgumentNullException();
}
public XNamespace Namespace { get { return Model.Name.Namespace; } }
public override string Name
{
get { return Model.Name.ToString(); }
}
}
Next, a couple extension classes:
public static class TreeViewExtensions
{
public static void PopulateNodes(this TreeView treeView, IEnumerable<ITreeNodeViewModel> viewNodes)
{
treeView.BeginUpdate();
try
{
treeView.Nodes.PopulateNodes(viewNodes);
}
finally
{
treeView.EndUpdate();
}
}
public static void PopulateNodes(this TreeNodeCollection nodes, IEnumerable<ITreeNodeViewModel> viewNodes)
{
nodes.Clear();
if (viewNodes == null)
return;
foreach (var viewNode in viewNodes)
{
var name = viewNode.Name;
var text = viewNode.Text;
if (string.IsNullOrEmpty(text))
text = name;
var node = new TreeNode { Name = name, Text = text, Tag = viewNode.Tag };
nodes.Add(node);
PopulateNodes(node.Nodes, viewNode.Children);
node.Expand();
}
}
}
public static class XObjectExtensions
{
public static string TextValue(this XContainer node)
{
if (node == null)
return null;
//return string.Concat(node.Nodes().OfType<XText>().Select(tx => tx.Value)); c# 4.0
return node.Nodes().OfType<XText>().Select(tx => tx.Value).Aggregate(new StringBuilder(), (sb, s) => sb.Append(s)).ToString();
}
public static IEnumerable<XElement> Elements(this IEnumerable<XElement> elements, XName name)
{
return elements.SelectMany(el => el.Elements(name));
}
}
Next, view models for the three levels of your tree:
class ContainerViewModel : XElementTreeNodeViewModel
{
public ContainerViewModel(XElement node) : base(node) { }
public override string Text
{
get
{
return Model.Element(Namespace + "ContainerName").TextValue();
}
}
public override IEnumerable<ITreeNodeViewModel> Children
{
get { return Enumerable.Empty<ITreeNodeViewModel>(); }
}
}
class ClassificationViewModel : XElementTreeNodeViewModel
{
public ClassificationViewModel(XElement node) : base(node) { }
public override string Text
{
get
{
return Model.Element(Namespace + "ClassificationName").TextValue();
}
}
public override IEnumerable<ITreeNodeViewModel> Children
{
get
{
return Model.Elements(Namespace + "Containers").Elements<XElement>(Namespace + "Container").Select(xn => (ITreeNodeViewModel)new ContainerViewModel(xn));
}
}
}
class GroupViewModel : XElementTreeNodeViewModel
{
public GroupViewModel(XElement node) : base(node) { }
public override string Text
{
get
{
return Model.Element(Namespace + "GroupName").TextValue();
}
}
public override IEnumerable<ITreeNodeViewModel> Children
{
get
{
return Model.Elements(Namespace + "Classifications").Elements<XElement>(Namespace + "Classification").Select(xn => (ITreeNodeViewModel)new ClassificationViewModel(xn));
}
}
}
Now, building your tree becomes quite simple:
var xdoc = XDocument.Load("ProductDocument.xml");
var ns = xdoc.Root.Name.Namespace;
treeView1.PopulateNodes(xdoc.Root.Elements(ns + "ProductGroup").Elements(ns + "Group").Select(xn => (ITreeNodeViewModel)new GroupViewModel(xn)));
And the result:
Later, if you wish to add editing functionality to your tree, you can add the appropriate methods to ITreeNodeViewModel -- for instance, a setter method for Text. Since the ITreeNodeViewModel has saved itself in the TreeNode.Tag the appropriate methods will be available.
So I have an xmlDocument and I need to check to see if a credit score was appended. To do this I am using xmlNodes.SelectSingleNode and then checking the innerText.
My issue is this: one of the nodes has an ID field in the actual node name. So I think C# is interpreting that as part of the node name.
public void DeperPostAppend()
{
DirectoryInfo CompDir = new DirectoryInfo(FilePrep.CompletedDirectory);
foreach (FileInfo File in CompDir.GetFiles())
{
// Load xml documents for sorting
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.Load(File.FullName);
}
catch
{
if (File.Extension != ".xml")
return;
}
//XmlNode auto = xmlDoc.SelectSingleNode("//ACORD//InsuranceSvcRq//PersAutoPolicyQuoteInqRq");
XmlNode home = xmlDoc.SelectSingleNode("//ACORD//InsuranceSvcRq//HomePolicyQuoteInqRq");
XmlNode creditAuto = xmlDoc.SelectSingleNode("//ACORD//InsuranceSvcRq//PersAutoPolicyQuoteInqRq//PersPolicy//CreditScoreInfo//CreditScore");
XmlNode creditHome = xmlDoc.SelectSingleNode("//ACORD//InsuranceSvcRq//HomePolicyQuoteInqRq//PersPolicy//CreditScoreInfo//CreditScore");
//if file is type home quote
if (File.Extension == ".xml" && creditHome != null)
{
if (creditHome.InnerText != "ERR" || creditHome.InnerText != "NOH")
{
DeperHome();
}
}
//If file is type Auto Quote
else if (File.Extension == ".xml" && creditAuto != null)
{
if (creditAuto.InnerText != "ERR" || creditAuto.InnerText != "NOH")
{
DeperAuto();
}
}
}
}//end DeperPostAppend
//ACORD//InsuranceSvcRq//HomePolicyQuoteInqRq//PersPolicy//CreditScoreInfo//CreditScore
PersPolicy is where the issue is. the node looks like this on the document.
<PersPolicy id="AE4562BEE086A92470D4">
I want to ignore the id portion due to the fact that it changes every document and i have thousands of docs to process.
I just decided to use classes to handle the nodes as follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
/// <summary>
///
/// </summary>
public class PersPolicy
{
XElement self;
public PersPolicy(XElement self) { this.self = self; }
public CreditScoreInfo CreditScoreInfo { get { return _CreditScoreInfo ?? (_CreditScoreInfo = new CreditScoreInfo(self.Element("CreditScoreInfo"))); } }
CreditScoreInfo _CreditScoreInfo;
public string PolicyNumber
{
get { return (string)self.Element("PolicyNumber"); }
set { self.Element("PolicyNumber").SetValue(value); }
}
}
/// <summary>
///
/// </summary>
public class CreditScoreInfo
{
XElement self;
public CreditScoreInfo(XElement self) { this.self = self; }
public string CreditScore
{
get { return (string)self.Element("CreditScore"); }
set { self.Element("CreditScore").SetValue(value); }
}
public string CreditScoreDt
{
get { return (string)self.Element("CreditScoreDt"); }
set { self.Element("CreditScoreDt").SetValue(value); }
}
}
This is my XML schema,
<Modules>
<Module name="Sales" path="../SalesInfo.xml" isEnabled="true" ... >
..............
</Module>
<Module name="Purchase" path="../PurchaseInfo.xml" isEnabled="true" ... >
..............
</Module>
................
</Module>
</Modules>
SalesInfo.XML
<Screens>
<Screen name="SalesOrder" ........ />
</Screen>
public class Module
{
public string Name
{
get;
set;
}
public string Type
{
get;
set;
}
.....
}
Here the modules and Screens are loaded on Request basis ("On Demand"). So i have to find the particular node when request comes(may be from menu click). Once the node is picked, it need to be converted to particular class. Eg when "sales" request comes, it should picked from XML and that need to converted to "Module" class. As one possible way is
Using XPathNavigator and find the Node.
Parse the "Finded Node" and convert to Particular class
This is bit complicated. I have to take care of all the attribute and its datatypes.
What i looking for
Find the Node
Convert the Node to My custom Class (I doesn't want to write code for Parser)
What is the Best approach. I'm working on C# 4.0.
EDIT:
XDocument document = XDocument.Load(path);
XElement mod = document.XPathSelectElement("Modules/Module[#name='PurchaseEnquiry']") as XElement;
Module purchaseModule = mod as Module; //This won't work, but i want like this.
Well... Not entirely sure what you are looking for here but I'll give it a shot.
You could read the content node by node and deserialize each node to your class like this:
public class XmlDataReader<T> : IEnumerable, IDisposable
{
private readonly XmlTextReader reader = null;
public XmlDataReader(string filename)
{
reader = new XmlTextReader(filename) {WhitespaceHandling = WhitespaceHandling.None};
reader.MoveToContent(); // Go to root node.
reader.Read(); // Go to first child node.
}
#region Implementation of IEnumerable
public IEnumerator GetEnumerator()
{
if (reader == null) yield break;
do
{
var ser = new XmlSerializer(typeof (T));
var subTree = reader.ReadSubtree();
subTree.MoveToContent();
var node = ser.Deserialize(subTree);
subTree.Close();
yield return node;
reader.Skip();
} while (!reader.EOF && reader.IsStartElement());
}
#endregion
#region Implementation of IDisposable
public void Dispose()
{
if (reader != null)
reader.Close();
}
#endregion
}
In your case you could use it like this:
var reader = new XmlDataReader<Module>("data.xml");
foreach (Module node in reader)
{
...
}
I am having problems serializing a cdata section using c#
I need to serialize XmlCDataSection object property as the innertext of the element.
The result I am looking for is this:
<Test value2="Another Test">
<![CDATA[<p>hello world</p>]]>
</Test>
To produce this, I am using this object:
public class Test
{
[System.Xml.Serialization.XmlText()]
public XmlCDataSection value { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute()]
public string value2 { get; set; }
}
When using the xmltext annotation on the value property the following error is thrown.
System.InvalidOperationException:
There was an error reflecting property
'value'. --->
System.InvalidOperationException:
Cannot serialize member 'value' of
type System.Xml.XmlCDataSection.
XmlAttribute/XmlText cannot be used to
encode complex types
If I comment out the annotation, the serialization will work but the cdata section is placed into a value element which is no good for what I am trying to do:
<Test value2="Another Test">
<value><![CDATA[<p>hello world</p>]]></value>
</Test>
Can anybody point me in the right direction to getting this to work.
Thanks, Adam
Thanks Richard, only now had chance to get back to this. I think I have resolved the problem by using your suggestion. I have created a CDataField object using the following:
public class CDataField : IXmlSerializable
{
private string elementName;
private string elementValue;
public CDataField(string elementName, string elementValue)
{
this.elementName = elementName;
this.elementValue = elementValue;
}
public XmlSchema GetSchema()
{
return null;
}
public void WriteXml(XmlWriter w)
{
w.WriteStartElement(this.elementName);
w.WriteCData(this.elementValue);
w.WriteEndElement();
}
public void ReadXml(XmlReader r)
{
throw new NotImplementedException("This method has not been implemented");
}
}
The way Test is defined, your data is a CData object. So the serialisation system is trying to preserve the CData object.
But you want to serialise some text data as a CData section.
So first, the type of Test.value should be String.
You then need to control how that field is serialised, but there does not appear to be any inbuilt method or attribute to control how strings are serialised (as string, maybe with entities for reserved characters, or as CDATA). (Since, from an XML infoset perspective all of these are the same, this is not surprising.)
You can of course implemented IXmlSerializable and just code the serialisation of the Test type yourself which gives you complete control.
This basically shorter version of Jack answer with better error messages:
[XmlIgnore]
public string Content { get; set; }
[XmlText]
public XmlNode[] ContentAsCData
{
get => new[] { new XmlDocument().CreateCDataSection(Content) };
set => Content = value?.Cast<XmlCDataSection>()?.Single()?.Data;
}
Just found an alternative from here:
[XmlIgnore]
public string Content { get; set; }
[XmlText]
public XmlNode[] CDataContent
{
get
{
var dummy = new XmlDocument();
return new XmlNode[] {dummy.CreateCDataSection(Content)};
}
set
{
if (value == null)
{
Content = null;
return;
}
if (value.Length != 1)
{
throw new InvalidOperationException(
String.Format(
"Invalid array length {0}", value.Length));
}
var node0 = value[0];
var cdata = node0 as XmlCDataSection;
if (cdata == null)
{
throw new InvalidOperationException(
String.Format(
"Invalid node type {0}", node0.NodeType));
}
Content = cdata.Data;
}
}
}
I had very same problem as Adam. However this Answer does not helped me at 100% :) but gives me a clue. So I'va created a code like below. It generates XML like this:
<Actions>
<Action Type="reset">
<![CDATA[
<dbname>longcall</dbname>
<ontimeout>
<url>http://[IPPS_ADDRESS]/</url>
<timeout>10</timeout>
</ontimeout>
]]>
</Action>
<Action Type="load">
<![CDATA[
<dbname>longcall</dbname>
]]>
</Action>
</Actions>
Code:
public class ActionsCDataField : IXmlSerializable
{
public List<Action> Actions { get; set; }
public ActionsCDataField()
{
Actions = new List<Action>();
}
public XmlSchema GetSchema()
{
return null;
}
public void WriteXml(XmlWriter w)
{
foreach (var item in Actions)
{
w.WriteStartElement("Action");
w.WriteAttributeString("Type", item.Type);
w.WriteCData(item.InnerText);
w.WriteEndElement();
w.WriteString("\r\n");
}
}
public void ReadXml(XmlReader r)
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(r);
XmlNodeList nodes = xDoc.GetElementsByTagName("Action");
if (nodes != null && nodes.Count > 0)
{
foreach (XmlElement node in nodes)
{
Action a = new Action();
a.Type = node.GetAttribute("Type");
a.InnerText = node.InnerXml;
if (a.InnerText != null && a.InnerText.StartsWith("<![CDATA[") && a.InnerText.EndsWith("]]>"))
a.InnerText = a.InnerText.Substring("<![CDATA[".Length, a.InnerText.Length - "<![CDATA[]]>".Length);
Actions.Add(a);
}
}
}
}
public class Action
{
public String Type { get; set; }
public String InnerText { get; set; }
}