02. juni 2006 - 15:27
Der er
15 kommentarer og 1 løsning
Recursive method vil ikke virke
Hejsa Jeg har et problem med denne her rekursive funktion, som looper et XML dokument igennem, og generere en htmlstring med tilsvarede <ul><li> elementer, afhæning af dybden. private string GenerateMenu(XmlNodeList menuNodes,string htmlMenu) { htmlMenu += "<ul>\n"; for(int i=0;i<menuNodes.Count;i++) { if(menuNodes[i].ChildNodes.Item(0).HasChildNodes) { XmlNode subMenuNode = menuNodes[i].ChildNodes.Item(0); XmlNodeList subMenuNodes = subMenuNode.ChildNodes; htmlMenu += "<li>"; htmlMenu += menuNodes[i].Attributes[0].Value + "\n"; htmlMenu += GenerateMenu(subMenuNodes,htmlMenu); htmlMenu += "</li>\n"; } else { htmlMenu += "<li>" + menuNodes[i].ChildNodes.Item(0).InnerText + "</li>\n"; } } htmlMenu += "</ul>"; return htmlMenu; } Lige nu får jeg følgende fejl: [NullReferenceException: Object reference not set to an instance of an object.] MenuView.GenerateMenu(XmlNodeList menuNodes, String htmlMenu) +73 MenuView.GenerateMenu(XmlNodeList menuNodes, String htmlMenu) +201 MenuView.Page_Load(Object sender, EventArgs e) +65 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +13 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +45 System.Web.UI.Control.OnLoad(EventArgs e) +98 System.Web.UI.Control.LoadRecursive() +71 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4308 Og den fejl siger mig ikke så meget, nogen som kan se fejlen?
Annonceindlæg fra Cognizant
Og den aktiveres ved: XmlDocument menuXML = new XmlDocument(); menuXML.Load("c:/IIS/hemmelig/menu/da.xml"); XmlNodeList menuNodes = menuXML.DocumentElement.ChildNodes; test.Text = GenerateMenu(menuNodes,"");
Du skal nok rette: if(menuNodes[i].ChildNodes.Item(0).HasChildNodes) - til: if(menuNodes[i].HasChildNodes)
nej :-) Fordi at C# betragter "foobar" i <m>foobar</m> som en childnode, og jeg ønsker kun at check hvis det var <m><m>foo</m><m>bar</m></m>
fejlmeddelsen er forresten debugget det at være her: htmlMenu += GenerateMenu(subMenuNodes,htmlMenu);
Den linje kan nu ikke generere den fejl. Fejlen ligger inden i selve funktionen. Og jo, den stemmer ganske pænt med at du muligvis begynder at forsøge at bruge en nodes children selv om der ikke er nogen: Hvis "menuNodes[i].HasChildNodes" er false, så vil "menuNodes[i].ChildNodes.Item(0)" give en nullpointer-exception.
ja, men hvis det er tilfældet, er problemet jo først når jeg looper subnodes, hvis jeg undlader linjen "htmlMenu += GenerateMenu(subMenuNodes,htmlMenu);" så looper den fint det overordnet set af data igennem, uden fejl.
Det skyldes sikkert at dit overordnede niveau jo *har* child-noder. Grunden til at den fejler når du tilføjer det rekursive kald, er at den så på et eller andet tidspunkt kommer så langt ud i dine noder, at den kommer til en node som ikke har child-noder. Og der fejler den så.
Her er XML delen: <?xml version="1.0" encoding="iso-8859-1"?> <menu lang="en"> <m>Frontpage</m> <m label="Products"> <m>Telephoning</m> <m>Broadband / ADSL</m> <m>Mobile Telephoning</m> <m label="Internet"> <m>Wireless</m> </m> <m>IP Telephoning</m> </m> <m label="Prices"> <m>Private</m> <m>Buisnesss</m> </m> <m>Order</m> <m label="Support"> <m>FAQ</m> <m>Support</m> <m>Performance</m> <m>Conditions</m> </m> <m>Contact</m> <m>Clientlogin</m> </menu>
Så hvordan får vi nu rette kode, så det virker ?
02. juni 2006 - 17:21
#10
jeg valgte at omskrive en hel del proev foelgende: using System; using System.Xml; namespace E { public class MainClass { private const string INDENT = " "; private static string GenerateMenu(XmlNode node, string indent) { string htmlMenu = ""; if(node.HasChildNodes && node.FirstChild.NodeType != XmlNodeType.Text) { if(indent.Length > 0) { htmlMenu += (indent + "<li>\n"); } if(node.Attributes.Count > 0) { htmlMenu += (indent + node.Attributes[0].Value + "\n"); } htmlMenu += (indent + "<ul>\n"); foreach(XmlNode newnode in node.ChildNodes) { htmlMenu += GenerateMenu(newnode, indent + INDENT); } htmlMenu += (indent + "</ul>\n"); if(indent.Length > 0) { htmlMenu += (indent + "</li>\n"); } } else { htmlMenu += (indent + "<li>" + node.InnerText + "</li>\n"); } return htmlMenu; } public static void Main(string[] args) { XmlDocument menuXML = new XmlDocument(); menuXML.Load(@"c:\test.xml"); Console.WriteLine(GenerateMenu(menuXML.DocumentElement, "")); } } }
02. juni 2006 - 18:49
#11
Nice. node.FirstChild.NodeType != XmlNodeType.Text var lige hvad jeg stod og manglede, og den foreach(x in) er også en del smartere. Mange tak. Points går til arne_v :-)
02. juni 2006 - 18:57
#12
svar
02. juni 2006 - 18:58
#13
Et sidste spørgsmål vis nogen skulle vide det. Hvilket asp.net element bør jeg binde min html string til ?
02. juni 2006 - 19:13
#14
Ingen anelse. Jeg tror slet ikke at det er den rigtige ASP.NET maade, men jeg kan ikke umiddelbart udpege et alternativ.
02. juni 2006 - 23:32
#15
Mit bud: private const string INDENT = " "; private static string GenerateMenu(XmlNodeList menuNodes, string indent) { string htmlMenu = indent + "<ul>\n"; string newIndent = indent + INDENT; for (int i = 0; i < menuNodes.Count; i++) { htmlMenu += newIndent + "<li>\n"; if (menuNodes[i].Attributes.Count > 0) { htmlMenu += newIndent + INDENT + menuNodes[i].Attributes["label"].Value + "\n"; htmlMenu += GenerateMenu(menuNodes[i].ChildNodes, newIndent); } else { htmlMenu += newIndent + INDENT + menuNodes[i].InnerText + "\n"; } htmlMenu += newIndent + "</li>\n"; } htmlMenu += indent + "</ul>\n"; return htmlMenu; }
09. juni 2006 - 09:11
#16
Et råd: lad være med at bruge rekursive funktioner, de bruger alt for meget CPU i forhold til at bruge f.eks. while loops. Men de er selvfølgelig sjove at lave.
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.