I am trying to display the data in this xml(~/server_settings.xml):
<?xml version="1.0" encoding="utf-8"?>
<site>
<general>
<name>Venture Corp</name>
<url>http://anerdsplayground.com/</url>
<developer>Otard95</developer>
</general>
<ore_contracts>
<use_system description="This is the system id the ore contract app gets its prices from">30000142</use_system>
</ore_contracts>
</site>
on my site. But I want to give it some style with css and add a form with input for each node that has a text value, so that I can later edit the content.
I want to be able to read any new nodes as well, as this file is going to expand in the future. So essentially it needs to read a dynamic xml.
I'm currently using this code:
@using System.Xml
@using System.Xml.Linq
@using System.Xml.XPath
@functions{
XmlDocument doc = null;
string output = "";
XmlDocument set_doc{
set{
doc = value;
}
}
string write_xml(string path){
// Add start tag and any attributes that this node may have
output += "<div ";
if(doc.SelectSingleNode(path).Attributes.Count > 0){
// As the description attribute is to be added to a p tag save it for later
string desc = "";
// loop through all attributes
foreach(XmlAttribute att in doc.SelectSingleNode(path).Attributes){
if(att.Name == "description"){ // If description attribute exists save it for later
desc = att.InnerText;
}else{ // Write attribute to output
output += att.Name + '=' + '"' + att.InnerText + '"' + ' ';
}
}
// Close starting tag
output += ">";
// If node has description attribute add to <p> tag
if(desc != ""){
output += "<p>" + desc + "</p><br/>";
}
}
// If current node has one or more child nodes execute this function for each of them
if(doc.SelectSingleNode(path).HasChildNodes){
foreach(XmlNode next_node in doc.SelectSingleNode(path).ChildNodes){
string new_path = path + "/" + next_node.Name; // Create path for next element
write_xml(new_path); // write next inner node
}
// Close this node
output += "</div>";
}else{ // No inner nodes add content of current node and close element
output += "<input type=" + '"' + "text" + '"' + " name=" + '"' + "node_content" + '"' + " value=" + '"' + doc.SelectSingleNode(path).InnerText + '"' + " />";
}
return output;
}
}
@{
// Get xml from eve-centeral with current ore-prices and creat dictionary
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("~/server_settings.xml"));
string root = "/site";
set_doc = doc;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<style>
</style>
</head>
<body>
@Html.Raw(write_xml(root));
</body>
</html>
But I get this error:
Server Error in '/' Application.
Expression must evaluate to a node-set.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Xml.XPath.XPathException: Expression must evaluate to a node-set.
Source Error:
Line 19: output += "<div ";
Line 20:
Line 21: error-->if(doc.SelectSingleNode(path).Attributes.Count > 0){
Line 22: // As the description attribute is to be added to a p tag save it for later
Line 23: string desc = "";
Line: 21
Stack Trace:
[XPathException: Expression must evaluate to a node-set.]
MS.Internal.Xml.XPath.XPathParser.ParseNodeTest(AstNode qyInput, AxisType axisType, XPathNodeType nodeType) +5596737
MS.Internal.Xml.XPath.XPathParser.ParseStep(AstNode qyInput) +75
MS.Internal.Xml.XPath.XPathParser.ParseRelativeLocationPath(AstNode qyInput) +18
MS.Internal.Xml.XPath.XPathParser.ParseLocationPath(AstNode qyInput) +118
MS.Internal.Xml.XPath.XPathParser.ParsePathExpr(AstNode qyInput) +30
MS.Internal.Xml.XPath.XPathParser.ParseUnionExpr(AstNode qyInput) +19
MS.Internal.Xml.XPath.XPathParser.ParseUnaryExpr(AstNode qyInput) +44
MS.Internal.Xml.XPath.XPathParser.ParseMultiplicativeExpr(AstNode qyInput) +21
MS.Internal.Xml.XPath.XPathParser.ParseAdditiveExpr(AstNode qyInput) +21
MS.Internal.Xml.XPath.XPathParser.ParseRelationalExpr(AstNode qyInput) +21
MS.Internal.Xml.XPath.XPathParser.ParseEqualityExpr(AstNode qyInput) +21
MS.Internal.Xml.XPath.XPathParser.ParseAndExpr(AstNode qyInput) +19
MS.Internal.Xml.XPath.XPathParser.ParseOrExpr(AstNode qyInput) +19
MS.Internal.Xml.XPath.XPathParser.ParseExpresion(AstNode qyInput) +30
MS.Internal.Xml.XPath.XPathParser.ParseXPathExpresion(String xpathExpresion) +54
System.Xml.XPath.XPathExpression.Compile(String xpath, IXmlNamespaceResolver nsResolver) +51
System.Xml.XPath.XPathNavigator.Select(String xpath) +14
System.Xml.XmlNode.SelectNodes(String xpath) +45
System.Xml.XmlNode.SelectSingleNode(String xpath) +7
ASP._Page_Administrative_Edit_Settings_cshtml.write_xml(String path) in c:\Users\Otard95\Google Drive\Personal\WebSites\VentureCorpDrive\Administrative\Edit_Settings.cshtml:21
ASP._Page_Administrative_Edit_Settings_cshtml.write_xml(String path) in c:\Users\Otard95\Google Drive\Personal\WebSites\VentureCorpDrive\Administrative\Edit_Settings.cshtml:46
ASP._Page_Administrative_Edit_Settings_cshtml.write_xml(String path) in c:\Users\Otard95\Google Drive\Personal\WebSites\VentureCorpDrive\Administrative\Edit_Settings.cshtml:46
ASP._Page_Administrative_Edit_Settings_cshtml.write_xml(String path) in c:\Users\Otard95\Google Drive\Personal\WebSites\VentureCorpDrive\Administrative\Edit_Settings.cshtml:46
ASP._Page_Administrative_Edit_Settings_cshtml.Execute() in c:\Users\Otard95\Google Drive\Personal\WebSites\VentureCorpDrive\Administrative\Edit_Settings.cshtml:78
System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +197
System.Web.WebPages.WebPage.ExecutePageHierarchy(IEnumerable`1 executors) +68
System.Web.WebPages.WebPage.ExecutePageHierarchy() +151
System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +76
System.Web.WebPages.WebPageHttpHandler.ProcessRequestInternal(HttpContextBase httpContext) +114
Desired output (example):
<html lang="en">
<body>
<div>NodeName:
<div any attributes xml node might have>
<p>value of attribute named "description"</p>
<form method="post">
<input type="text" name="node_content" value="current content of xml node"/>
</form>
</div>
</div>
<div any attributes xml node might have>
<p>value of attribute named "description"</p>
<form method="post">
<input type="text" name="node_content" value="current content of xml node"/>
</form>
</div>
...
</body>
</html>
I'm quite new to the System.xml namespace so this might not be the best way to do it. But as I have not found a good tutorial, my only choice has been to use the method of trial and error. So if you do decide to reply please explain a little. And if you have a good tutorial handy, a link maybe, I'd greatly appreciate it.
If I missed anything and you need more info, please give me a heads-up and I'll Edit the post as soon as I can.
Thanks in advance for any help you might provide!
As @har07 suggested i found the value of the path
variable when the exception occurs, and I got /site/general/name/#text
. What i did not know was that the text content of a XmlElement
was considered a ChildNode
Solution:
if(doc.SelectSingleNode(path).HasChildNodes && doc.SelectSingleNode(path).FirstChild.GetType().ToString() != "System.Xml.XmlText"){
foreach(XmlNode next_node in doc.SelectSingleNode(path).ChildNodes){
string new_path = path + "/" + next_node.Name; // Create path for next element
write_xml(new_path); // write next inner node
}
// Close this node
output += "</div>";
}else{
Edit:
Added && doc.SelectSingleNode(path).FirstChild.GetType().ToString() != "System.Xml.XmlText"
to if
statement
Many thanks to you @har07