Как найти атрибут с помощью HTMLDocument?

#java #html #dom #attributes

#java #HTML #dom #атрибуты

Вопрос:

Возможно, терминология HTML отличается от XML, но вот HTML-документ, из которого извлекаются атрибуты. Здесь атрибуты a1, a2, a3 являются частью тега Body .

 <html>
  <head>
      Hello World
  </head>
  <body a1="ABC" a2="3974" a3="A1B2">     <------These attributes
    <H1>Start Here<H1>
    <p>This is the body</p>
  </body>
</html>
  

Используя следующий файл для анализа вышеупомянутого HTML-файла.

 import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;

import javax.swing.text.AttributeSet;
import javax.swing.text.Element;
import javax.swing.text.ElementIterator;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;

public class HTMLParserTest
{

  public static void main(String args[]) throws Exception {

    Reader reader = new FileReader("C:/Downloads/DeleteMe/Example1.html");
    BufferedReader br = new BufferedReader(reader );

    HTMLEditorKit htmlKit = new HTMLEditorKit();
    HTMLDocument htmlDoc = (HTMLDocument) htmlKit.createDefaultDocument();
    HTMLEditorKit.Parser parser = new ParserDelegator();
    HTMLEditorKit.ParserCallback callback = htmlDoc.getReader(0);
    parser.parse(br, callback, true);
    
    // Parse
    ElementIterator iterator = new ElementIterator(htmlDoc);
    Element element;
    while ((element = iterator.next()) != null) 
    {
      System.out.println("Element : "   element);
      AttributeSet attributes = element.getAttributes();
      Object name = attributes.getAttribute(StyleConstants.NameAttribute);
      if ((name instanceof HTML.Tag))
          //amp;amp; ((name == HTML.Tag.H1) || (name == HTML.Tag.H2) || (name == HTML.Tag.H3))) 
        {
        // Build up content text as it may be within multiple elements
        StringBuffer text = new StringBuffer();
        int count = element.getElementCount();
        for (int i = 0; i < count; i  ) {
          Element child = element.getElement(i);
          AttributeSet childAttributes = child.getAttributes();
          System.out.println("Element : "   child);
          System.out.println("     Attribute count : "   childAttributes.getAttributeCount());
          System.out.println("     a1 exists : "   childAttributes.isDefined("a1"));
          
            int startOffset = child.getStartOffset();
            int endOffset = child.getEndOffset();
            int length = endOffset - startOffset;
            text.append(htmlDoc.getText(startOffset, length));
        }
        
      }
    }
    System.exit(0);
  }
}
  

Вывод здесь.

 Element : BranchElement(html) 0,1

Element : BranchElement(body) 0,1

     Attribute count : 1
     a1 exists : false                    <-----expected true here.
Element : BranchElement(body) 0,1

Element : BranchElement(p) 0,1

     Attribute count : 3
     a1 exists : false
Element : BranchElement(p) 0,1

Element : LeafElement(content) 0,1

     Attribute count : 1
     a1 exists : false
Element : LeafElement(content) 0,1
  

Ожидается, что проверка «a1 существует» должна была вернуть true один раз, но этого не произошло.
В конечном итоге будут найдены все 3 (a1, a2, a3).

Является ли приведенный выше код правильной реализацией или это невозможно с помощью синтаксического анализатора HTML?

Комментарии:

1. Ищите современный синтаксический анализатор, совместимый с HTML5. В Java их много.

Ответ №1:

Может быть, это поможет:

 import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;

class AttributeHTML
{
    public static void main(String[] args)
    {
        EditorKit kit = new HTMLEditorKit();
        Document doc = kit.createDefaultDocument();

        // The Document class does not yet handle charset's properly.
        doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);

        try
        {
            // Create a reader on the HTML content.
            Reader rd = getReader(args[0]);

            // Parse the HTML.
            kit.read(rd, doc, 0);

            // Iterate through the elements of the HTML document.

            ElementIterator it = new ElementIterator(doc);
            Element elem = null;

            while ( (elem = it.next()) != null )
            {
                if (elem.getName().equals("body"))
                {

                    AttributeSet as = elem.getAttributes();

                    Enumeration enum1 = as.getAttributeNames();

                    while( enum1.hasMoreElements() )
                    {
                        Object name = enum1.nextElement();
                        Object value = as.getAttribute( name );

                        System.out.println( "t"   name   " : "   value );
                    }

                }
            }

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        System.exit(1);
    }

    // Returns a reader on the HTML data. If 'uri' begins
    // with "http:", it's treated as a URL; otherwise,
    // it's assumed to be a local filename.
    static Reader getReader(String uri)
        throws IOException
    {
        // Retrieve from Internet.
        if (uri.startsWith("http:"))
        {
            URLConnection conn = new URL(uri).openConnection();
            return new InputStreamReader(conn.getInputStream());
        }
        // Retrieve from file.
        else
        {
            return new FileReader(uri);
        }
    }
}
  

Тест с использованием:

 java AttributeHTML yourFile.html
  

Комментарии:

1. Спасибо. Это то, что я пытался сделать, но, очевидно, с треском провалился. Работает хорошо.

Ответ №2:

Я не знаю, HtmlKit но вы можете добиться аналогичного результата, используя регулярное выражение

 public static void main(String[] args) throws UnirestException {
    String html = "<html>rn"   
            "  <head>rn"   
            "      Hello Worldrn"   
            "  </head>rn"   
            "  <body a1="ABC" a2="3974" a3="A1B2">rn"   
            "    <H1>Start Here<H1>rn"   
            "    <p>This is the body</p>rn"   
            "  </body>rn"   
            "</html>";
    Pattern regexBodyPattern = Pattern.compile("<body[^>]*>", Pattern.MULTILINE);
    Matcher matcher = regexBodyPattern.matcher(html);
    
    while(matcher.find()) {
        String bodyTag = matcher.group();
        Pattern regexBodyAttrPattern = Pattern.compile("(\S*)=(\"\w*\")", Pattern.MULTILINE);
        Matcher attrMatcher = regexBodyAttrPattern.matcher(bodyTag);
        while(attrMatcher.find()) {
            System.out.println("Key :: " attrMatcher.group(1) " , Value " attrMatcher.group(2));
        }
    }       
}
  

вывод

 Key :: a1 , Value "ABC"
Key :: a2 , Value "3974"
Key :: a3 , Value "A1B2"
  

Комментарии:

1. Спасибо. Меня беспокоит только то, что если содержимое изменится, это может потребовать изменения шаблона регулярных выражений. (Не уверен, так как не слишком много работал с ним.)

2. @Необработанное исключение если вам нужно найти атрибуты тега body, это регулярное выражение будет работать для чтения всех атрибутов.

Ответ №3:

Чтобы получить атрибуты, вы можете предоставить свой собственный parserc обратный вызов

 import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;
import javax.swing.text.html.parser.ParserDelegator;

public class HTMLParserTest2
{

  public static void main(String args[]) throws Exception {

    Reader reader = new FileReader("d:/temp/Example.html");
    BufferedReader br = new BufferedReader(reader);
    
    System.out.println(HTMLParserTest2.extractTagsAttributes(br));
    // output :  [title-_implied_=true, body-a1=ABC, body-a2=3974, body-a3=A1B2]
    System.exit(0);
  }
  
  public static List<String> extractTagsAttributes(Reader r) throws IOException {
     final ArrayList<String> list = new ArrayList<String>();

     ParserDelegator parserDelegator = new ParserDelegator();
     ParserCallback parserCallback = new ParserCallback() {
       @Override
      public void handleText(final char[] data, final int pos) {  }
       @Override
      public void handleStartTag(Tag tag, MutableAttributeSet attribute, int pos) { 
          Enumeration<?> e=attribute.getAttributeNames();
          while(e.hasMoreElements()) {
             Object name=e.nextElement();
             Object value=attribute.getAttribute(name);
             list.add(tag.toString()   "-"   name   "="  value);
          }
       }
      @Override
      public void handleEndTag(Tag t, final int pos) {  }
      @Override
      public void handleSimpleTag(Tag t, MutableAttributeSet a, final int pos) { }
      @Override
      public void handleComment(final char[] data, final int pos) { }
      @Override
      public void handleError(final java.lang.String errMsg, final int pos) { }
     };
     parserDelegator.parse(r, parserCallback, true);
     return list;
  }
}