I am building an xml document and I have declared the namespace at the very top.
<Root xmlns="http://www.omg.org/space/xtce" xmlns:xtce="http://www.omg.org/space/xtce" ...>
At some arbitrary level below I want to AppendChild with an element created from a string. My goal is to end up with a document that contains that element without the xmlns AT ALL.
This is the closest I have gotten-
string someElementStr = "<SomeElement name="foo"><SubElement name="bar" /></SomeElement>";
XmlDocumentFragment node = doc.CreateDocumentFragment();
node.InnerXml = someElementStr;
someXmlNodeWithinDoc.AppendChild(node);
This code results in-
<SomeElement name="foo" xmlns="">
<SubElement name="bar" />
</SomeElement>
in the final document.
I use a different construct when I do not have to go from a string to XML-
XmlElement elem = doc.CreateElement("SomeElement", "http://www.omg.org/space/xtce");
elem.SetAttribute("name","foo");
someXmlNodeWithinDoc.AppendChild(elem);
and this yields exactly what I want.
<SomeElement name="foo">
</SomeElement>
I would like to do something line this in my current solution
node.setNamespace("http://www.omg.org/space/xtce") then the document would omit xmlns because it is same as root.
Can someone tell me the idiomatic way to build a document with a single namespace use within, where some elements are stored in the model as a string?
This issue is almost identical to mine except the solution has the luxury of only providing the sub element as a string (everything under "new"). I need the entire element.
string xmlRoot = "<Root xmlns=\"http://www.omg.org/space/xtce\"></Root>";
string xmlChild = "<SomeElement name=\"foo\"><SubElement name = \"bar\"/></SomeElement >";
XDocument xDoc = XDocument.Parse(xmlRoot);
XDocument xChild = XDocument.Parse(xmlChild);
xChild.Root.Name = xDoc.Root.GetDefaultNamespace() + xChild.Root.Name.LocalName;
foreach (XElement xChild2 in xChild.Root.Nodes())
{
xChild2.Name = xDoc.Root.GetDefaultNamespace() + xChild2.Name.LocalName;
}
xDoc.Root.Add(xChild.Root);
string xmlFinal = xDoc.ToString();
This is the solution I ended up with. I did not use #shop350 solution because I didn't want to use XDocument,XElement... Thank you for the feedback though!
// create a fragment which I am going to build my element based on text.
XmlDocumentFragment frag = doc.CreateDocumentFragment();
// here I wrap my desired element in another element "dc" for don't care that has the namespace declaration.
string str = "";
str = "<dc xmlns=\"" + xtceNamespace + "\" ><Parameter name=\"paramA\" parameterTypeRef=\"paramAType\"><AliasSet><Alias nameSpace=\"ID\" alias=\"0001\"/></AliasSet></Parameter></dc>";
// set the xml for the fragment (same namespace as doc)
frag.InnerXml = str;
// let someXmlNodeWithinDoc be of type XmlNode which I determined based on XPath search.
// Here I attach the child element "Parameter" to the XmlNode directly effectively dropping the element <dc>
someXmlNodeWithinDoc.AppendChild(frag.FirstChild.FirstChild);
Related
I have a XML file like this:
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd">
<ServerConfiguration>
<SecurityPolicies>
<ServerSecurityPolicy>
<SecurityMode>None_1</SecurityMode>
</ServerSecurityPolicy>
</SecurityPolicies>
</ServerConfiguration>
</ApplicationConfiguration>
What I want is to add more node named ServerSecurityPolicy by code.
Then I use this code:
string docaddress = "D:\\abc.xml";
XDocument doc = XDocument.Load(docaddress);
var root = doc.Root;
var these = root.Descendants().Where(p => p.Name.LocalName == "SecurityPolicies");
XElement addelement = new XElement("ServerSecurityPolicy");
addelement.Add(new XElement("SecurityMode", "None_1"));
foreach (var elem in these)
{
elem.Add(addelement);
}
doc.Save(docaddress);
It actually works, but the newly added node is something like this:
<ServerSecurityPolicy xmlns="">
<SecurityMode>None_1</SecurityMode>
</ServerSecurityPolicy>
I don't want the attribute "xmlns", then I try to delete it by something like this:
var these2 = root.Descendants().Where(p => p.Name.LocalName == "ServerSecurityPolicy");
foreach (var elem in these2)
{
label2.Text += elem.Attribute("xmlns").Name.LocalName;
elem.Attribute("xmlns").Remove();
}
The label2.Text shows "xmlnsxmlnsxmlsn..." so that I think the elem.Attribute("xmlns") has pointed to the attributes I want to delete, but the Remove() not work.
Can you suggest me some ways to delete the attribute or add node without attribute?
Thank you
The reason you're getting an empty attribute - which xmlns="" refers to - is because your document's root node belongs to the namespace xsi. When you're adding a node without a namespace - as you're doing in your example - you're not actually binding it to the xsi namespace.
To make your node part of the root namespace, replace
new XElement("ServerSecurityPolicy")
with
new XElement("ServerSecurityPolicy",
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"))
The problem is that the element you want to create is actually in the http://opcfoundation.org/UA/SDK/Configuration.xsd namespace, which is the default for the document because of this part of the root element:
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
You can create an element in that namespace easily:
XNamespace configNs = "http://opcfoundation.org/UA/SDK/Configuration.xsd";
var these = root.Descendants(configNs + "ServerSecurityPolicy");
When you add that to your document, you'll find it won't add the xmlns="" part, which was present because you were adding an element without a namespace.
I'd also suggest using the namespace to find elements too:
XNamespace configNs = "http://opcfoundation.org/UA/SDK/Configuration.xsd";
var these = root.Descendants(configNs + "SecurityPolicies");
That's much cleaner than just using the local name, in my view.
i have to fill up an XML file from a DATA TABLE ,my problem is that i have to get the schemaLocation in the root node ,for this i use the code below ,then i have this result,and i dont know where is p1 coming from
In your resulting XML, p1 is a namespace. The code you have posted (in a screenshot) is defining the namespace "xsi", I'm not sure why your result is generating p1 unless you are renaming xsi somewhere that is not shown.
XmlDocument doc = new XmlDocument();
XmlDeclaration declaire = doc.CreateXmlDeclaration("1.0", "utf-8", null);
XmlElement rootnode = doc.CreateElement("BMECAT");
doc.InsertBefore(declaire, doc.DocumentElement);
doc.AppendChild(rootnode);
rootnode.SetAttribute("version", "2005");
XmlAttribute atr = doc.CreateAttribute("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
atr.Value = "http://www.adlnet.org/xsd/adlcp.vlp3";
rootnode.SetAttributeNode(atr);
rootnode.Attributes.Append(atr);
In your code:
XmlAttribute atr = doc.CreateAttribute("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
"xsi" is the name of the namespace it generates, you can control it there. This results in:
<?xml version="1.0" encoding="utf-8"?>
<BMECAT version="2005" xsi:schemaLocation="http://www.adlnet.org/xsd/adlcp.vlp3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
I'm not sure your code matches the result file you provided. When I ran the code, I get "xsi" as expected. If I set "xsi" to null there, it uses a default name, which in my case was d1p1. All instances of "xsi" were replaced with "d1p1". This makes me believe that code might be slightly different from what generated your result. I don't know where "d1p1" came from, it's likely a generated default namespace. This seems like a common default (Remove "d1p1" namespace prefix in DataContractSerializer XML output). In your provided code, if you change "xsi" to "p1" you would get your result.
I might suggest using this method instead:
How to Add schemaLocation attribute to an XML document
Here you would use the accepted answer against your XmlElement rootnode.
XmlElement.SetAttributeValue (localname, prefix, namespace, value)
Please try this code and let me know whether this helped you or not.
Particularly in this code i parse XML file and get the root element:
Then use it to select all attributes named schemaLocation. There is only one, so you can use SelectSingleNode:
The variable
schemaLocationAttribute
Contanins Value attribute through which you can get actual value.
XmlReader xmlReader = XmlReader.Create("MyXML.xml");
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(xmlReader);
XmlElement root = xmlDocument.DocumentElement;
XmlNode schemaLocationAttribute = root.SelectSingleNode("//#*[local-name()='schemaLocation']");
//Single schema value
string schemaValue = schemaLocationAttribute.Value;
//If you have multiple values in your schema
//you have to store it inside of array
string[] multipleShcemavalues = schemaLocationAttribute.Value.Split(null);
//And you have to choose whuickelement you want to use
string chooosendShcema = multipleShcemavalues[1]; //For example
How to get the xml node value in a string.
i am getting This error
Data at the root level is invalid. Line 1, position 1.
error shown in this line
xmldoc.LoadXml(xmlFile);
my xml
<?xml version="1.0" encoding="utf-8" ?>
<UOM>
<!-- The selected currency used will be stored here for Code reference" -->
<ActiveCurrencyType>
<ActiveCurrency>U.S.Dollar</ActiveCurrency>
<ActiveCode>USD</ActiveCode>
<ActiveSymbol>$</ActiveSymbol>
</ActiveCurrencyType>
<!-- The selected Dimension used will be stored here for Code reference -->
<ActiveDimension>
<ActiveDimensionUOM>Inches</ActiveDimensionUOM>
<ActiveDimensionSymbol>.in</ActiveDimensionSymbol>
</ActiveDimension>
<!-- The selected weight used will be stored here for Code reference -->
<ActiveWeight>
<ActiveWeightUOM>Pounds</ActiveWeightUOM>
<ActiveWeightSymbol>lb</ActiveWeightSymbol>
</ActiveWeight>
</UOM>
C# code
string xmlFile = Server.MapPath("~/HCConfig/HCUOM.xml");
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlFile);
XmlNodeList nodeList = xmldoc.GetElementsByTagName("ActiveDimensionSymbol");
string ActiveDimensionSymbol = string.Empty;
foreach (XmlNode node in nodeList)
{
ActiveDimensionSymbol = node.InnerText;
}
How can I achieve this?
You're using the wrong overload, LoadXml doesn't do what you think it does.
Use xmldoc.Load(xmFile); because that method takes an file path as input. LoadXml expects an string with xml in it.
The exception is an indicator of that mistake. What is processed is not XML, and a filepath isn't that.
After this changes the string ActiveDimensionSymbol contains .in if I run this locally.
If you want to use LoadXml you should first read your whole file in a string, for example like so:
xmldoc.LoadXml(File.ReadAllText(xmlFile));
but is really only overhead to call File.ReadAllText if there is an method that accepts a file.
You can use the Descendants() method to get all XElements by certain name, found in the System.Xml.Linq namespace.
XDocument doc = XDocument.Load("XMLFile1.xml");
string[] allActiveWeightUOMs = doc.Descendants("ActiveWeightUOM").Select(o => o.Value).ToArray();
// allActiveWeightUOMs : "Pounds" ...
As can seen here link the method that you are using to load the XML excepts xml by string not xml file. You can use XmlDocument.Load instead of XmlDocument.LoadXml
Try this code its works just fine with this xml
string xmlFile = Server.MapPath("~/HCConfig/HCUOM.xml");
XDocument doc = XDocument.Load(xmlFile );
var nodeList = doc.Descendants("ActiveDimensionSymbol");
string ActiveDimensionSymbol = string.Empty;
foreach (var node in nodeList)
{
ActiveDimensionSymbol = node.Value;
}
I have XML String:
<GroupBy Collapse=\"TRUE\" GroupLimit=\"30\">
<FieldRef Name=\"Department\" />
</GroupBy>
<OrderBy>
<FieldRef Name=\"Width\" />
</OrderBy>
I am new in C#. I tried to read the Name attribute of the FieldRef element for both elements but I could not. I used XMLElement , is there any way to pick these two values?
Despite the posting of invalid XML (no root node), an easy way to iterate through the <FieldRef> elements is to use the XmlReader.ReadToFollowing method:
//Keep reading until there are no more FieldRef elements
while (reader.ReadToFollowing("FieldRef"))
{
//Extract the value of the Name attribute
string value = reader.GetAttribute("Name");
}
Of course a more flexible and fluent interface is provided by LINQ to XML, perhaps it would be easier to use that if available within the .NET framework you are targeting? The code then becomes:
using System.Xml.Linq;
//Reference to your document
XDocument doc = {document};
/*The collection will contain the attribute values (will only work if the elements
are descendants and are not direct children of the root element*/
IEnumerable<string> names = doc.Root.Descendants("FieldRef").Select(e => e.Attribute("Name").Value);
try this:
string xml = "<GroupBy Collapse=\"TRUE\" GroupLimit=\"30\"><FieldRef Name=\"Department\" /></GroupBy><OrderBy> <FieldRef Name=\"Width\" /></OrderBy>";
xml = "<root>" + xml + "</root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode node in doc.GetElementsByTagName("FieldRef"))
Console.WriteLine(node.Attributes["Name"].Value);
I have a C# application that uses a button to generate a file. Currently, I want to use C# to extract out contents from the XML file and pass it as a string. For example in my XML file, I have a tag name. I want to use c# to extract the name from the XML file. How should I go about achieving it? Below is the sample code I have currently. The entire process must be carried out using a button click.
private void button1_Click(object sender, EventArgs e)
{
XElement xml = XElement.Load("C:\\Windows 7.xml");
IEnumerable<XElement> propertyIDs = xml.Descendants("PropertyId");
foreach (XElement child in xml.Elements())
{
XElement row = child.Element("my:VM_Name");
string test = xml.ToString();
Console.WriteLine(test);
}
}
Please access this link to view my xml file: http://pastebin.com/NKhBb4Zh
I rewrote your example and changed it to make use of the XmlDocument class. As there is the my Namespace I had to add a NameSpaceManager. using this you may even select a spefic node.
string url = #"e:\temp\data.xml";
XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(url);
XmlElement docElement = doc.DocumentElement;
/// loop through all childNodes
foreach (XmlNode childNode in docElement.ChildNodes)
{
Console.WriteLine(childNode.Name + ": " + childNode.InnerText);
}
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2011-05-27T03:57:48");
/// use the given XmlNamespaceManager to select a specific element
XmlNode node = docElement.SelectSingleNode("my:VM_DiskSize", mgr);
/// use innerText for node text and value for attributes only
Console.WriteLine("\n" + node.Name + ": " + node.InnerText);
hth
The comments you added to your question were very helpful. In particular:
I added this code:
XElement name = xml.Element("my:VM_Name");
string test = xml.ToString();
Console.WriteLine(test);
But I am still unable to extract out Windows 7 from the XML tag
And:
i get this error The ':' character, hexadecimal value 0x3A, cannot be included in a name.
Let's start with the error first. You cannot pass to the Element method an ns:name pair as you've done. With this API, the namespace (ns) must be supplied programatically via the XName type. So instead, that line should read:
XElement name = xml.Element(XName.Get("VM_Name", "my"));
Here we pass the qualified name as an actual XName and not as a colon-delimited string as it originates. Pay attention to the order; the namespace comes second using this syntax.
Now, once you have done all this, the other line in which you have a problem is:
string test = xml.ToString();
Here, xml refers to your root XML node whereas what you actually want is, presumably, the element for which you just queried: xml.Element(XName.Get("VM_Name", "my")). Furthermore, to get the text contents of that node, you should use the Value property. I suspect what you really want is:
string test = name.Value;