supposing O have these two equivalent (at least they are supposed to be) XML schemas. The actual XML will eventually be parsed by C#. I think the second way is 'more correct' since I will get attributes as actual attrbutes, instead of child elements, correct?
<?xml version="1.0" encoding="ISO-8859-1"?>
<switch>
<switch_name>switch1</switch_name>
<software_version>1</software_version>
<vendor>Cisco</vendor>
<ip_address>1.1.1.1</ipaddress>
<linecard>
<model_type>12345</model_type>
<fcport>
<slot> 1</slot>
<port> 1</port>
<speed>4</speed>
</fcport>
</linecard>
</switch>
<switch>
<switch name="switch1" version="1" vendor="Cisco" ip_address="1.1.1.1">
<linecard model="12345">
<fcport slot="1" port="1" speed="4">
</fcport>
<linecard>
</switch>
</xml>
Neither one is strictly more "correct" than the other, both will work for your example. Neither breaks any rules.
That said, I think I agree with W3Schools on this one, in that data should go inside child elements rather than attributes. Especially things like IP addresses just FEEL like data that should be a child element rather than an attribute. Attributes I typically use for metadata, such as auto generated IDs.
This is especially true if you later want to account for expansion -- for example, what if you want to associate multiple IPs? With child elements you can just add another element, but with attributes you have to come up with a new attribute name for each addition (ip1, ip2, ip3...).
There are no "right" way of representing data in XML when choosing between using elements or attributes for properties of an entity. Choose whatever works for you.
Generally elements give more freedom as you may have sub-elements eventually. I.e. if property is list of some sort representing it as comma-separated value in attribute looks very non-XML.
Side note: "XML schema" usually means different thing - structured schema for XML... what you have I'd call "representation of data in XML".
The classic article on how to choose between elements and attributes is here:
http://xml.coverpages.org/elementsAndAttrs.html
I note that at the end of the page it quotes John Cowan quoting me: "Beginnners always ask this question. Those with a little experience express their opinions passionately. Experts tell you there is no right answer'."
Related
I am saving xml from .NET's XElement. I've been using the method ToString, but the formatting doesn't look how I'd like (examples below). I'd like at most two tags per line. How can I achieve that?
Saving XElement.Parse("<a><b><c>one</c><c>two</c></b><b>three<c>four</c><c>five</c></b></a>").ToString() gives me
<a>
<b>
<c>one</c>
<c>two</c>
</b>
<b>three<c>four</c><c>five</c></b>
</a>
But for readability I would rather 'three', 'four' and 'five' were on separate lines:
<a>
<b>
<c>one</c>
<c>two</c>
</b>
<b>three
<c>four</c>
<c>five</c>
</b>
</a>
Edit: Yes I understand this is syntactically different and "not in the spirit of xml", but I'm being pragmatic. Recently I've seen megabyte-size xml files with as few as 3 lines—these are challenging to text editors, source control, and diff tools. Something needs to be done! I've tested that changing the formatting above is compatible with our application.
If you want exactly that output, you'll need to do it manually, adding whitespace around nodes as necessary.
Almost all whitespace in XML documents is significant, even if we only think of it as indenting. When we ask the serializer to indent the document for us, it is making changes to the content that can get extracted, so they try to be as conservative as possible. The elements
<tag>foo</tag>
and
<tag>
foo
</tag>
have different content, and if an serializer changed the former into the latter, it would change what you get back from your XML API when asking for the contents of <tag>.
The usual rule of thumb is that no indenting will be applied if there's any existing non-whitespace between the elements. In this case, your three between the tags would be modified if a serializer applied the indenting you desire, so nothing will do it for you automatically.
If you have control over the XML format, it's inadvisable to mix element and text children like this, where <b> has both text (three) and element (<c>) children, as it causes issues like what you're seeing.
The formatting isn't working the way you want because of the naked "three". Is there a reason it's not in it's own tag? Should it be an attribute of "b" instead?
Explained reasons to colleagues - we're going to change the file format. I recommend you try to do the same. It's nigh impossible to do what I wanted, because most xml tools assume whitespace is significant.
XML is an information exchange format, intended for computers. The whitespace is irrelevant (depending on location and schema, really) and as such, it would be arbitrary to use one or the other.
You could use XmlTextWriter with XElement.Save and see whether you can tweak it to your liking with the XmlWriter.Settings Property
I've had to do something similar before (for a client request). All I ended up doing was writing a custom .ToString() method only used for either displaying the XML in a browser(ugh, i know) or for their use in downloading an xml file of the content. Because the code did not have to be computationally efficient, it was merely a matter of checking the children of each tag and arranging the 'hanging' text as such.
Eventually we were able to convince the user that the text should be an attribute instead.
Currently I have a solution that builds an XML document in a number of sections and then validates the final concatenated xml against a single schema. Is it possible to use a subset of the same schema to validate each section individually?
The answer is yes in most of the cases. For a disclaimer, in theory someone could intentionally write an XML Schema that would make some of my proposals impossible, but then that would be just bad practice in XSD authoring.
For a straightforward solution, the following assumptions should be true:
A section is well formed XML; you're concatenating XmlElement nodes. E.g.:
<section-element ... attribute content>
... more content
</section-element>
Each of the sections being merged has a matching global element declaration in your XML Schema set. If you use the xsi:type attribute for any of your sections, things might get a bit tricky, but not hard to fix.
The validation would be common code, where the XmlReader would be an XmlNodeReader on the node you're concatenating. Use the XmlReaderSettings as usual...
The above would work for any XSD (you don't have a design time dependency of knowing the XSD). For anything below, the code would have to match your XSD...
If you don't have the matching global elements in the XML Schema then you have to look at the type of each matching local element declaration. If the type is global, then you can easily create, in memory, dummy elements that match your sections, of the global type (assuming a Venetian Blind authoring style).
If even the type is anonymous (more of a Russian Doll style), then you can even fake that, by creating a global element with a type that is a copy of the anonymous type - all in memory.
I have an XSD file and want to get a list of the names of all the elements in it. I don't mean stuff like <xs:sequence> and so on, just the "real stuff", that actually can appear in XML that are valid according to the XSD.
Real stuff is a bit vague
But if you just want want all elements it's just a it of Xpath.
If you want a tree, then you can't avoid sequence etc.
If you have things like xs:choice in there you have even more issues.
Then there's attributes...
From SimpleContent or ComplexType...
Might be easier to generate a 'blank' xml document from the xsd and then get what you want out of that. That's a fair chunk of code as well though. Might be one lying around you can borrow though.
If you don't actually want to do this from your code, you could use the XML Schema Definition Tool (Xsd.exe) to create source code for runtime objects.
From there you can use Xml serialization to create valid Xml samples for your given Xsd schema.
Since you're trying to code for this, I would assume you want to do this against different XML Schema files, over and over; if true, it would be then important to understand if you really have to embed this in your codebase, or if it can be used as an external tool.
If you really want to do it, most of all you need is in System.Xml.Schema package. Start with an XmlSchemaSet to load and compile your XSD files. Then using an iterator on GlobalElements, go over the global elements that can show as your root elements in XML document and traverse those (for what you need, use the PSVI properties); as someone else was mentioning, there will be types to go through, compositors, etc.; and then there's more: abstract elements (those can't show up in XML, neither references to abstract elements, instead members of substitution groups), prohibited attributes, restricted types, etc.
I've recently answered another post that may be related to your need; your posted XML Schema may look like this:
root/ship/engine/#MaxSpeed,A,1..1,True
root/ship/crew/#function,A,1..1,True
root/ship/#Name,A,1..1,True
root/ship/#class,A,1..1,True
root/ship/special_abilities/hull/#separable,A,0..1,False
root/ship/special_abilities/hull/#canCarryWesley,A,0..1,False
root/ship/special_abilities/hull/#capableOfLanding,A,0..1,False
If you want, you can deal only with the first column; the generated XPath shows only those items (elements or attributes) that have data; processing something like the above might be much easier (split the string using /, elements are all but #, etc.)
I'm using XML to hold some settings, so let's go with the following example:
<PermissionLevels>
<Permission Name="MyPermission 1" Bases="XXX" />
<Permission Name="MyPermission 2" Bases="XXX" />
</PermissionLevels>
So the XXX is my problem. I will have several base permissions, e.g. "Read, Create, Delete", and I know C# has the .Split method, so I could probably try it with "," as a delimiter. I could also have child nodes to <Permission>.
Is there a correct way to do it? With correct I mean the following: I'm not sure whether I should use LINQ (XDocument) or the regular System.Xml variant (XmlDocument) and I am not sure if some different way might be better to handle.
With .Split I will have to take the node.Attributes["Base"].Value, split it and do a foreach for all elements in the array - maybe LINQ is smarter and can do something differently?
Sorry for my rambling, this is just not my domain. The question actually is: When I have multiple values for one attribute, do I concatenate them with e.g. a ",", or do I do it differently (e.g. with child nodes of the object)?
I would prefer child nodes. Attributes are meant for scalar (single) values.
Also, this way your source code in C# with LINQ will be simple and that's good.
Is it possible to use variables like <%=person.LastName %> in XML string this way?
XElement letters = new XElement("Letters");
XElement xperson = XElement.Parse("<Table><Row><Cell><Text>
<Segment>Dear <%=person.Title%> <%=person.FirstName%> <%=person.LastName%>,
</Segment></Text></Cell></Row>...");
foreach (Person person in persons){
letters.Add(xperson)
}
If it's possible, it would be a lifesaver since I can't use XElement and XAttribute to add the nodes manually. We have multiple templates and they frequently change (edit on the fly).
If this is not doable, can you think of another way so that I can use templates for the XML?
Look like it's possible in VB
http://aspalliance.com/1534_Easy_SQL_to_XML_with_LINQ_and_Visual_Basic_2008.6
This is an exclusive VB.NET feature known as XML Literals. It was added in VB 9.0. C# does not currently support this feature. Although Microsoft has stated its intent to bridge the gap between the languages in the future, it's not clear whether this feature will make it to C# any time soon.
Your example doesn't seem clear to me. You would want to have the foreach loop before parsing the actual XML since the values are bound to the current Person object. For example, here's a VB example of XML literals:
Dim xml = <numbers>
<%= From i In Enumerable.Range(1, 5)
Select <number><%= i %></number>
%>
</numbers>
For Each e In xml.Elements()
Console.WriteLine(e.Value)
Next
The above snippet builds the following XML:
<numbers>
<number>1</number>
<number>2</number>
<number>3</number>
</numbers>
Then it writes 1, 2, 3 to the console.
If you can't modify your C# code to build the XML dynamically then perhaps you could write code that traverses the XML template and searches for predetermined fields in attributes and elements then sets the values as needed. This means you would have to iterate over all the attributes and elements in each node and have some switch statement that checks for the template field name. If you encounter a template field and you are currently iterating attributes you would set it the way attributes are set, whereas if you were iterating elements you would set it the way elements are set. This is likely not the most efficient approach but is one solution.
The simplest solution would be to use VB.NET. You can always develop it as a stand-alone project, add a reference to the dll from the C# project, pass data to the VB.NET class and have it return the final XML.
EDIT: to clarify, using VB.NET doesn't bypass the need to update the template. It allows you to specify the layout easier as an XML literal. So code still needs to be updated in VB once the layout changes. You can't load an XML template from a text file and expect the fields to be bound that way. For a truly dynamic solution that allows you to write the code once and read different templates my first suggestion is more appropriate.