Avatar billede tdafoobar Nybegynder
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?
Avatar billede tdafoobar Nybegynder
02. juni 2006 - 15:28 #1
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,"");
Avatar billede nielle Nybegynder
02. juni 2006 - 15:32 #2
Du skal nok rette:

if(menuNodes[i].ChildNodes.Item(0).HasChildNodes)

- til:

if(menuNodes[i].HasChildNodes)
Avatar billede tdafoobar Nybegynder
02. juni 2006 - 15:33 #3
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>
Avatar billede tdafoobar Nybegynder
02. juni 2006 - 15:33 #4
fejlmeddelsen er forresten debugget det at være her:

htmlMenu += GenerateMenu(subMenuNodes,htmlMenu);
Avatar billede nielle Nybegynder
02. juni 2006 - 15:42 #5
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.
Avatar billede tdafoobar Nybegynder
02. juni 2006 - 15:47 #6
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.
Avatar billede nielle Nybegynder
02. juni 2006 - 15:51 #7
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å.
Avatar billede tdafoobar Nybegynder
02. juni 2006 - 15:53 #8
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>
Avatar billede tdafoobar Nybegynder
02. juni 2006 - 15:53 #9
Så hvordan får vi nu rette kode, så det virker ?
Avatar billede arne_v Ekspert
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, ""));
        }
    }
}
Avatar billede tdafoobar Nybegynder
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 :-)
Avatar billede arne_v Ekspert
02. juni 2006 - 18:57 #12
svar
Avatar billede tdafoobar Nybegynder
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 ?
Avatar billede arne_v Ekspert
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.
Avatar billede nielle Nybegynder
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;
        }
Avatar billede rudidanmark Nybegynder
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.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester