2014-11-06 3 views
0

Я пытаюсь получить «NAME» и «E-MAIL» тексты из следующего HTML-файла:Как получить внутренний текст из XML-документа с помощью XDocument и расширения методов

<!DOCTYPE html> 

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <meta charset="utf-8" /> 
    <title></title> 
</head> 
<body> 
    <ol> 
     <li> 
      <font class="normal"> 
       <b>NAME</b> <a href="/member/mail_compose.aspx?id=name"><img src="/images/mailbox.gif" border="0" alt="Send Mail" /></a> <a href="/photos/member_viewphoto.aspx?id=name"><img src="/images/icons/member_photos.gif" border="0" alt="View Photos" /></a> <br /> 
       ADDRESS<br /> 
       PHONE<br /> 
       <a href="mailto:[email protected]" class="redlink">EMAIL</a><br /> 
       <br /> 
      </font> 
     </li> 
</body> 
</html> 

Вот код, который Я использую:

// Load the xml document 
XDocument xDoc = XDocument.Load(@"..\..\Directory.html"); 

// Parse document 
var names = xDoc.Root.DescendantsAndSelf() 
     .Where(x => x.Name.LocalName == "ol").DescendantsAndSelf() 
     .Where(x => x.Name.LocalName == "li").DescendantsAndSelf() 
     .Select(x => new 
         { 
          name = x.Elements().Where(y => y.Name.LocalName == "b").Select(y => y.Value), 
          email = x.DescendantsAndSelf().Where(y => y.Name.LocalName == "a" && x.FirstAttribute.Name == "href" && x.Attribute("href").Value.Contains("mailto")).Select(y => y.Value ?? "No Email") 
         } 
     ); 

// Print text to console 
for (int i = 0; i < names.Count(); i++) 
{ 
    Console.WriteLine("{0}: {1}", names.ElementAt(i).name, names.ElementAt(i).email); 
} 

Каким-то образом, приведенный выше код печатает это:

System.Linq.Enumerable + WhereSelectEnumerableIterator 2[System.Xml.Linq.XElement, System.String]: System.Linq.Enumerable+WhereSelectEnumerableIterator 2 [System.Xm l.Linq.XElement, System.String]

Может кто-то пожалуйста, скажите мне, почему это происходит? Кроме того, если есть лучший способ сделать это, предложения будут очень желанными.

ответ

0

Чтобы ответить на ваш первый вопрос (что, вероятно, более важно для вас, чем код, который я должен заставить его работать для этого образца HTML), у вас есть. Выберите для своего имени и поля электронной почты. Вот почему вы возвращаете коллекцию, когда вы перебираете имена. Если это действительно то, что вам нужно, тогда выберите SelectMany вместо Select при создании анонимного объекта.

Без схемы, я не знаю, как лучше ваш XML, пересекающей перед «.select»

Другой проблемой является то, что для HREF атрибута, необходимо сравнить с FirstAttribute.Name.LocalName вместо только FirstAttribute.Name

var names = xDoc.Root.DescendantsAndSelf() 
       .Where(x => x.Name.LocalName == "ol").DescendantsAndSelf() 
       .Where(x => x.Name.LocalName == "li").DescendantsAndSelf() 
       .Where(x => x.Name.LocalName == "font") 
       .Select(x => new 
       { 
        name = x.Descendants().Where(y => y.Name.LocalName == "b").Select(y => y.Value).Single(), 
        email = x.Descendants().Where(y => y.Name.LocalName == "a" && y.FirstAttribute.Name.LocalName == "href" && y.Attribute("href").Value.Contains("mailto")).Select(y => y.Value).Single() 
       }); 

Некоторые примечания:

y.Value ?? "No Email" 

потребности быть переделано, потому что y.Value никогда не будет аннулирована
также вы отсутствовали в ола тег в HTML :)

1

Без проверки на нуль (обратите внимание на большинство мест, которые я использую FirstOrDefault потенциально может thrrow NullExceptions, так как я не проверить нуль в растворе.

var htmlToProcess = 
@"<!DOCTYPE html> 
           <html lang='en' xmlns='http://www.w3.org/1999/xhtml'> 
           <head> 
            <meta charset='utf-8' /> 
            <title></title> 
           </head> 
           <body> 
            <ol> 
             <li> 
              <font class='normal'> 
               <b>NAME</b> <a href='/member/mail_compose.aspx?id=name'><img src='/images/mailbox.gif' border='0' alt='Send Mail' /></a> <a href='/photos/member_viewphoto.aspx?id=name'><img src='/images/icons/member_photos.gif' border='0' alt='View Photos' /></a> <br /> 
               ADDRESS<br /> 
               PHONE<br /> 
               <a href='mailto:[email protected]' class='redlink'>EMAIL</a><br /> 
               <br /> 
              </font> 
             </li> 
            </ol> 
           </body> 
           </html>"; 
     var body = dataSet1Tree.Nodes() 
           .OfType<XElement>() 
           .FirstOrDefault(x=> x.Name.LocalName.ToLower() =="body"); 

     if (body != null) 
     { 
      var oi = body.Descendants() 
         .FirstOrDefault(x => x.Name.LocalName.ToLower() == "ol"); 
      if (oi != null) 
      { 
       var lis = oi.Elements() 
          .Where(x=> x.Name.LocalName.ToLower()=="li"); 
       var listContainingInfo =from font in lis.Select(li => body.Descendants() 
                      .FirstOrDefault(x => x.Name.LocalName.ToLower() == "font")) 
                 .Where(font => font != null) 
             select font.Nodes().OfType<XElement>(); 

       var listOfUsers = listContainingInfo.Select(nodes => new 
       { 
        Name = nodes.FirstOrDefault(innerNode => innerNode.Name.LocalName.ToLower() == "b").Value, 
        Email = nodes.FirstOrDefault(innerNode => innerNode.Value == "EMAIL") 
           .Attributes("href") 
           .FirstOrDefault() 
           .Value 
       }); 

       foreach (var user in listOfUsers) 
        Console.WriteLine(user.Name +" "+ user.Email); 


      } 
     } 
+0

Этот ответ также работает, но я отмечаю другой правильный ответ как ответ, потому что он был опубликован первым. Спасибо за ваш ответ. – Tom

 Смежные вопросы

  • Нет связанных вопросов^_^