I'm serializing a xml string with the following code
StringReader newStringReader = new StringReader(value.Value);
try
{
using (var reader = XmlReader.Create(newStringReader))
{
newStringReader = null;
writer.WriteNode(reader, false);
}
}
finally
{
if (newStringReader != null)
newStringReader.Dispose();
}
but in the written xml file I have
<property i:type="string">
<name>Test</name>
<value>
</value>
</property>
but correct would be
<property i:type="string">
<name>Test</name>
<value></value>
</property>
since the "value" property is an empty string. The way it is serialized not it returns "\r\n ".
Writer:
XmlTextWriter writer = new XmlTextWriter(output);
try { writer.Formatting = System.Xml.Formatting.Indented;
writer.Indentation = 2; // Konfiguration sichern
WriteConfiguration(config, writer);
}
finally { writer.Close(); }
What have I done wrong?
UPDATE:
I write a xml configuration file. The values can either be ints, bools, etc or other xml strings. These xml strings are written with the code above. It works fine except for emtpy string elements in the xml string.
UPDATE 2:
It works if I manually change the xml string I want to write. I replace all
<tag></tag>
by
<tag/>
Unfortunatley it's not really a "proper" solution to modify a string with regexes.
I have always had far better luck with the formatting of XML documents when I work with them as XDocument types and simply use the Save method. For example xmlDoc.Save("C:\temp\xmlDoc.xml"); Simple as that. Also with this you can save over and over throughout the editing with little performance hit (at least none that I have noticed).
I would say this is caused by the indentation parameters. Did you try setting the Indented property to false?
I'm writing an xml file with settings. In this file can also be other xml documents. The code above ensures that it's not written in a single line with > etc but as xml in xml. So I have to work with the WriteNode-Method.
try removing
writer.Formatting = System.Xml.Formatting.Indented;
writer.Indentation = 2;
lines, and see what happens.
We did overcome this problem by using short tags of the form...
<value />
...instead of...
<value></value>
...then you can't have line breaks in the XML output. To do this, you have to query your tree before passing it to the writer.
/// <summary>
/// Prepares the XML Tree, to write short format tags, instead
/// of an opening and a closing tag. This leads to shorter and
/// particularly to valid XML files.
/// </summary>
protected static void Sto_XmlShortTags(XmlNode node)
{
// if there are children, make a recursive call
if (node.ChildNodes.Count > 0)
{
foreach (XmlNode childNode in node.ChildNodes)
Sto_XmlShortTags(childNode);
}
// if the node has no children, use the short format
else
{
if (node is XmlElement)
((XmlElement)node).IsEmpty = true;
}
}
Related
I'm working with a 3rd party application that takes input in via XML, and then returns the input back out in XML, I'm looking for a way to format the information to display it nicely in a richtextbox.
<Solution>
<ID>1</ID>
<Property>
<Name>DriverSheave</Name>
<Value>1VP34</Value>
</Property>
<Property>
<Name>DriverBushing</Name>
<Value>
</Value>
</Property>
<Property>
<Name>DrivenSheave</Name>
<Value>AK49</Value>
this is some sample xml that i would receive as an output from the 3rd party app, What I'm currently doing is this.
richTextBox1.Text = Configurator.Results.InnerText.ToString();
which gives me results like this.
1DriverSheave3MVP55B69DriverBushingDrivenSheave3MVB200RDrivenBushingR1BeltB225BeltQty3
essentially id like to know the best way to move these around, and make the output formatted nicely. so im not asking that you format this for me, but rather let me know the proper way to go about formatting this.
id like it to look similar to
Refer to the below code:
using System.XML.Linq;
class XMLParseProgram
{
public DataTable ReadXML(string strXML)
{
XDocument xdoc = XDocument.Load(strXML);
var property= from props in xdoc.Element("Solution").Elements("Property").ToList().ToList();
if (property!= null)
{
DataTable dtItem = new DataTable();
dtItem.Columns.Add("Name");
dtItem.Columns.Add("Value");
foreach (var itemDetail in property.ElementAt(0))
{
dtItem.Rows.Add();
if (itemDetail.Descendants("Name").Any())
dtItem.Rows[count]["Name"] = itemDetail.Element("Name").Value.ToString();
if (itemDetail.Descendants("Value").Any())
dtItem.Rows[count]["Value"] = itemDetail.Element("Value").Value.ToString();
}
}
}
}
You can use the DataTable to generate the string in your program the way you want.
If one of Configurator or Configurator.Results is an XmlDocument or XmlElement you can use one of these converters to an XElement:
richTextBox1.Text = Configurator.Results.ToXElement().ToString();
I have the following XML
<?xml version="1.0"?>
<DisplayViewHtml>
<embeddedHTML><![CDATA[<html><body><div>Hello World</div></body></html>]]></embeddedHTML>
<executive>Madan Mishra</executive>
<imgSRC>/executive/2.jpg</imgSRC>
</DisplayViewHtml>
In the c# code trying to extract the value of embeddedHTML with out CDATA.
My c# code is given below,
XElement displayViewHtml=null;
XmlReader reader = XmlReader.Create(new StringReader(e.Result));
displayViewHtml = XElement.Load(reader);
IEnumerable<XElement> settings = from item in displayViewHtml.Elements() select item;
foreach (XElement setting in settings)
{
switch (setting.Name.ToString())
{
case "embeddedHTML":
counterViewHtml = setting.Value;
break;
case "executive":
executive = setting.Value;
break;
case "imgSRC":
imgSRC = setting.Value;
break;
default:
//log
break;
}
}
from the above code I am able to extract the value of embeddedHTML,executive and imgSRC But embeddedHTML gives
<![CDATA[<html><body><div>Hello World</div></body></html>]]>
but I want
<html><body><div>Hello World</div></body></html>
kindly don't suggest to use .Replace method
As #CamBruce suggested, the problem is that your xml file has encoded characters where they shouldn't. Ideal solution is to fix the program that generate xml file. Anyway if you, for some reason expect a work-around here, this way will do :
.....
case "embeddedHTML":
var element = XElement.Parse("<embeddedHtml>" +
setting.Value +
"</embeddedHtml>");
counterViewHtml = element.Value;
break;
.....
The codes above tell the program to create new XElement (which is variable element) by parsing string that already unescaped. Hence, value of newly created XElement will contains string that you want :
<html><body><div>Hello World</div></body></html>
It looks like the CData declaration in the XML is encoded with the rest of the HTML. Ensure that the producer of this XML has the non-encoded CData declaration, like this <![CDATA[ encoded HTML content ]]>
Otherwise, the code you have looks correct. There is nothing special you need to do to read CData with Linq to XML.
To start, I am constrained to .NET 2.0 so LINQ is not an option for me (though I would be curious to see a LINQ solution as fodder for pushing to move to .NET 3.5 for the project if it is easy).
I have an XSD that is turned into a set of C# classes via xsd.exe at build time. At runtime, an XML file is loaded and deserialized into the C# classes (validation occurs at this time). I need to then turn that in-memory configuration object (including the default values that were populated during import of the XML file) into a dictionary of key value pairs.
I would like the dictionary key to be a dot separated path to the value. Attribute values and element text would be considered values, everything else along the way a key into that.
As an example, imagine the following XML file:
<rootNode>
<foo enabled="true"/>
<bar enabled="false" myAttribute="5.6">
<baz>Some Text</baz>
<baz>Some other text.</baz>
</bar>
</rootNode>
would turn into a dictionary with keys like:
"rootNode.foo.enabled" = (Boolean)true
"rootNode.bar.enabled" = (Boolean)false
"rootNode.bar.myAttribute" = (Float)5.6
"rootNode.bar.baz" = List<String> { "Some Text", "Some other text." }
Things of note are that rootNode is left off not because it is special but because it had no text or attributes. Also, the dictionary is a dictionary of objects which are typed appropriately (this is already done in deserialization, which is one of the reasons I would like to work with the C# object rather than the XML directly).
Interestingly, the objects created by xsd.exe are already really close to the form I want. The class names are things like rootNodeFoo with a float field on it called myAttribute.
One of the things I have considered but am not sure how to go about are using reflection to iterate over the object tree and using the names of the classes of each object to figure out the name of the node (I may have to tweak the casing a bit). The problem with this is that it feels like the wrong solution since I already have access to a deserializer that should be able to do all of that for me and much faster.
Another option would be using XSLT to serialize the data directly to a format that is how I want. The problem here is that my XSLT knowledge is limited and I believe (correct me if I am wrong) I will lose typing on the way (everything will be a string) so I will have to essentially deserialize once again by hand to get the types back out (and this time without XSD validation that I get when I use the .NET deserializer).
In case it matters, the calls I am using to get the configuration object populated from an XML file is something like this:
var rootNode = new XmlRootAttribute();
rootNode.ElementName = "rootNode";
rootNode.Namespace = "urn:myNamespace";
var serializer = new XmlSerializer(typeof(rootNode), rootNode);
using (var reader = new StringReader(xmlString))
{
var deserializedObject = (rootNode)serializer.Deserialize(reader);
}
First observation: using the object graph is not the best place to start to generate a dot representation. You're talking about nodes which have names and are in a well-defined hierarchy and you want to produce some kind of dot notation from it; the xml DOM seems to be the best place to do this.
There are a few problems with the way you describe the problem.
The first is in the strategy when it comes to handling multiple elements of the same name. You've dodged the problem in your example by making that dictionary value actually a list, but suppose your xml looked like this:
<rootNode>
<foo enabled="true">
<bar enabled="false" myAttribute="5.6" />
<bar enabled="true" myAttribute="3.4" />
</foo>
</rootNode>
Besides foo.enabled = (Boolean)true which should be fairly obvious, what dictionary keys do you propose for the two myAttribute leaves? Or would you have a single entry, foo.bar.myAttribute = List<float> {5.6, 3.4}? So, problem #1, there's no unambiguous way to deal with multiple similarly-named non-leaf nodes.
The second problem is in selecting a data type to do the final conversion at leaf nodes (i.e. attribute or element values). If you're writing to a Dictionary<string, object>, you will probably want to select a type based on the Schema simple type of the element/attribute being read. I don't know how to do that, but suggest looking up the various uses of the System.Convert class.
Assuming for the moment that problem #1 won't surface, and that you're ok with a Dictionary<string, string> implementation, here's some code to get you started:
static void Main(string[] args)
{
var xml = #"
<rootNode>
<foo enabled=""true"">
<bar enabled=""false"" myAttribute=""5.6"" />
<baz>Text!</baz>
</foo>
</rootNode>
";
var document = new XmlDocument();
document.LoadXml(xml);
var retVal = new Dictionary<string, string>();
Go(retVal, document.DocumentElement, new List<string>());
}
private static void Go(Dictionary<string, string> theDict, XmlElement start, List<string> keyTokens)
{
// Process simple content
var textNode = start.ChildNodes.OfType<XmlText>().SingleOrDefault();
if (textNode != null)
{
theDict[string.Join(".", keyTokens.ToArray())] = textNode.Value;
}
// Process attributes
foreach (XmlAttribute att in start.Attributes)
{
theDict[string.Join(".", keyTokens.ToArray()) + "." + att.Name] = att.Value;
}
// Process child nodes
foreach (var childNode in start.ChildNodes.OfType<XmlElement>())
{
Go(theDict, childNode, new List<string>(keyTokens) { childNode.Name }); // shorthand for .Add
}
}
And here's the result:
One approach would be to implement a customer formatter and slot it into the standard serialization pattern, create a class that implements IFormatter i.e. MyDotFormatter
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iformatter.aspx
then implement as below
Stream stream = File.Open(filename, FileMode.Create);
MyDotFormatter dotFormatter = new MyDotFormatter();
Console.WriteLine("Writing Object Information");
try
{
dotFormatter.Serialize(stream, objectToSerialize);
}
catch (SerializationException ex)
{
Console.WriteLine("Exception for Serialization data : " + ex.Message);
throw;
}
finally
{
stream.Close();
Console.WriteLine("successfully wrote object information");
}
When I load this XML node, the HTML within the node is being completely stripped out.
This is the code I use to get the value within the node, which is text combined with HTML:
var stuff = innerXml.Descendants("root").Elements("details").FirstOrDefault().Value;
Inside the "details" node is text that looks like this:
"This is <strong>test copy</strong>. This is A Link"
When I look in "stuff" var I see this:
"This is test copy. This is A Link". There is no HTML in the output... it is pulled out.
Maybe Value should be innerXml or innerHtml? Does FirstOrDefault() have anything to do with this?
I don't think the xml needs a "cdata" block...
HEre is a more complete code snippet:
announcements =
from link in xdoc.Descendants(textContainer).Elements(textElement)
where link.Parent.Attribute("id").Value == Announcement.NodeId
select new AnnouncmentXml
{
NodeId = link.Attribute("id").Value,
InnerXml = link.Value
};
XDocument innerXml;
innerXml = XDocument.Parse(item.InnerXml);
var abstract = innerXml.Descendants("root").Elements("abstract").FirstOrDefault().Value;
Finally, here is a snippet of the Xml Node. Notice how there is "InnerXml" within the standard xml structure. It starts with . I call this the "InnerXml" and this is what I am passing into the XDocument called InnerXml:
<text id="T_403080"><root> <title>How do I do stuff?</title> <details> Look Here Some Form. Please note that lorem ipsum dlor sit amet.</details> </root></text>
[UPDATE]
I tried to use this helper lamda, and it will return the HTML but it is escaped, so when it displays on the page I see the actual HTML in the view (it shows instead of giving a link, the tag is printed to screen:
Title = innerXml.Descendants("root").Elements("title").FirstOrDefault().Nodes().Aggregate(new System.Text.StringBuilder(), (sb, node) => sb.Append(node.ToString()), sb => sb.ToString());
So I tried both HTMLEncode and HTMLDecode but neither helped. One showed the escaped chars on the screen and the other did nothing:
Title =
System.Web.HttpContext.Current.Server.HtmlDecode(
innerXml.Descendants("root").Elements("details").Nodes().Aggregate(new System.Text.StringBuilder(), (sb, node) => sb.Append(node.ToString()), sb => sb.ToString())
);
I ended up using an XmlDocument instead of an XDocument. It doesn't seem like LINQ to XML is mature enough to support what I am trying to do. THere is no InnerXml property of an XDoc, only Value.
Maybe someday I will be able to revert to LINQ. For now, I just had to get this off my plate. Here is my solution:
// XmlDoc to hold custom Xml within each node
XmlDocument innerXml = new XmlDocument();
try
{
// Parse inner xml of each item and create objects
foreach (var faq in faqs)
{
innerXml.LoadXml(faq.InnerXml);
FAQ oFaq = new FAQ();
#region Fields
// Get Title value if node exists and is not null
if (innerXml.SelectSingleNode("root/title") != null)
{
oFaq.Title = innerXml.SelectSingleNode("root/title").InnerXml;
}
// Get Details value if node exists and is not null
if (innerXml.SelectSingleNode("root/details") != null)
{
oFaq.Description = innerXml.SelectSingleNode("root/details").InnerXml;
}
#endregion
result.Add(oFaq);
}
}
catch (Exception ex)
{
// Handle Exception
}
I do think wrapping your details node in a cdata block is the right decision. CData basically indicates that the information contained within it should be treated as text, and not parsed for XML special characters. The html charaters in the details node, especially the < and > are in direct conflict with the XML spec, and should really be marked as text.
You might be able to hack around this by grabbing the innerXml, but if you have control over the document content, cdata is the correct decision.
In case you need an example of how that should look, here's a modified version of the detail node:
<details>
<![CDATA[
This is <strong>test copy</strong>. This is A Link
]]>
</details>
I have a string :
responsestring = "<?xml version="1.0" encoding="utf-8"?>
<upload><image><name></name><hash>SOmetext</hash>"
How can i get the value between
<hash> and </hash>
?
My attempts :
responseString.Substring(responseString.LastIndexOf("<hash>") + 6, 8); // this sort of works , but won't work in every situation.
also tried messing around with xmlreader , but couldn't find the solution.
ty
Try
XDocument doc = XDocument.Parse(str);
var a = from hash in doc.Descendants("hash")
select hash.Value;
you will need System.Core and System.Xml.Linq assembly references
Others have suggested LINQ to XML solutions, which is what I'd use as well, if possible.
If you're stuck with .NET 2.0, use XmlDocument or even XmlReader.
But don't try to manipulate the raw string yourself using Substring and IndexOf. Use an XML API of some description. Otherwise you will get it wrong. It's a matter of using the right tool for the job. Parsing XML properly is a significant chunk of work - work that's already been done.
Now, just to make this a full answer, here's a short but complete program using your sample data:
using System;
using System.Xml.Linq;
class Test
{
static void Main()
{
string response = #"<?xml version='1.0' encoding='utf-8'?>
<upload><image><name></name><hash>Some text</hash></image></upload>";
XDocument doc = XDocument.Parse(response);
foreach (XElement hashElement in doc.Descendants("hash"))
{
string hashValue = (string) hashElement;
Console.WriteLine(hashValue);
}
}
}
Obviously that will loop over all the hash elements. If you only want one, you could use doc.Descendants("hash").Single() or doc.Descendants("hash").First() depending on your requirements.
Note that both the conversion I've used here and the Value property will return the concatenation of all text nodes within the element. Hopefully that's okay for you - or you could get just the first text node which is a direct child if necessary.
var val = XElement.Parse();
val.Descendants(...).Value
Get your xml well formed and escape the double quotes with backslash. Then apply the following code
XDocument resp = XDocument.Parse("<hash>SOmetext</hash>");
var r= from element in resp.Elements()
where element.Name == "hash"
select element;
foreach (var item in r)
{
Console.WriteLine(item.Value);
}
You can use an xmlreader and/or xpath queries to get all desired data.
XmlReader_Object.ReadToFollowing("hash");
string value = XmlReader_Object.ReadInnerXml();