代码之家  ›  专栏  ›  技术社区  ›  Kevin Coppock

使用SAXParser从XML检索HTML编码文本

  •  1
  • Kevin Coppock  · 技术社区  · 15 年前

    这是我第一次使用SAXParser(我在Android中使用它,但我认为这对这个特定的问题没有影响),我正在尝试从RSS提要读取数据。到目前为止,它对我的大部分工作都很好,但是当它到达一个包含HTML编码文本的标记时,我遇到了麻烦(例如。 &lt;a href="http://... ). 这个 characters() 方法只读取 &lt; < ,然后将下一组字符视为单独的实体,而不是一次获取整个内容。我更希望它只是照原样读入,而不是真正翻译HTML。我用于文档处理程序(简称)的代码发布在下面:

    @Override
        public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
            if (localName.equalsIgnoreCase("channel")) {
                inChannel = true;
            }
            if (inChannel) {
                if (newFeed == null) newFeed = new Feed();
    
                if (localName.equalsIgnoreCase("image")) {
                    if (feedImage == null) feedImage = new Image();
                    inImage = true;
                }
    
                if (localName.equalsIgnoreCase("item")) {
                    if (newItem == null) newItem = new Item();
                    if (itemList == null) itemList = new ArrayList<Item>();
                    inItem = true;
                }
            }   
        }
    
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if(!inItem) {
                if(!inImage) {
                    if(inChannel) {
                        //Reached end of feed
                        if(localName.equalsIgnoreCase("channel")) {
                            newFeed.setItems((ArrayList<Item>)itemList);
                            finalFeed = newFeed;
                            newFeed = null;                     
                            inChannel = false;
                            return;
                        } else if(localName.equalsIgnoreCase("title")) {
                            newFeed.setTitle(currentValue); return;
                        } else if(localName.equalsIgnoreCase("link")) {
                            newFeed.setLink(currentValue); return;
                        } else if(localName.equalsIgnoreCase("description")) {
                            newFeed.setDescription(currentValue); return;
                        } else if(localName.equalsIgnoreCase("language")) {
                            newFeed.setLanguage(currentValue); return;
                        } else if(localName.equalsIgnoreCase("copyright")) {
                            newFeed.setCopyright(currentValue); return;
                        } else if(localName.equalsIgnoreCase("category")) {
                            newFeed.addCategory(currentValue); return;
                        }                       
                    }
                }
                else { //is inImage
                    //finished with feed image
                    if(localName.equalsIgnoreCase("image")) {
                        newFeed.setImage(feedImage);
                        feedImage = null;
                        inImage = false;
                        return;
                    } else if (localName.equalsIgnoreCase("url")) {
                        feedImage.setUrl(currentValue); return;
                    } else if (localName.equalsIgnoreCase("title")) {
                        feedImage.setTitle(currentValue); return;
                    } else if (localName.equalsIgnoreCase("link")) {
                        feedImage.setLink(currentValue); return;
                    }
                }
            }
            else { //is inItem
                //finished with news item
                if (localName.equalsIgnoreCase("item")) {
                    itemList.add(newItem);
                    newItem = null;
                    inItem = false;
                    return;
                } else if (localName.equalsIgnoreCase("title")) {
                    newItem.setTitle(currentValue); return;
                } else if (localName.equalsIgnoreCase("link")) {
                    newItem.setLink(currentValue); return;
                } else if (localName.equalsIgnoreCase("description")) {
                    newItem.setDescription(currentValue); return;
                } else if (localName.equalsIgnoreCase("author")) {
                    newItem.setAuthor(currentValue); return;
                } else if (localName.equalsIgnoreCase("category")) {
                    newItem.addCategory(currentValue); return;
                } else if (localName.equalsIgnoreCase("comments")) {
                    newItem.setComments(currentValue); return;
                } /*else if (localName.equalsIgnoreCase("enclosure")) {
                     To be implemented later
                }*/ else if (localName.equalsIgnoreCase("guid")) {
                    newItem.setGuid(currentValue); return;
                } else if (localName.equalsIgnoreCase("pubDate")) {
                    newItem.setPubDate(currentValue); return;
                }           
            }
        }
    
        @Override
        public void characters(char[] ch, int start, int length) {
            currentValue = new String(ch, start, length);
        }
    

    我试图解析的RSS提要的一个例子是 this one .

    有什么想法吗?

    3 回复  |  直到 15 年前
        1
  •  4
  •   Ian Stanton    15 年前

    精彩的。这个解决方案让我有点困惑,我无法像您那样获得localName的值,但是我仍然能够使用StringBuilder方法。

    我没有替换方法:

    public void characters(char[] ch, int start, int length) throws SAXException {

    tempVal = new String(ch,start,length);

    tempSB = tempSB.append(new String(ch, start, length));
    

    其中tempSB是StringBuilder对象。 这意味着我不需要修改整个解析器,只需在必要时切换到读取SB。

    tempSB.delete(0, tempSB.length());
    

    为了讨人喜欢,我用了:

    tempText.setText(tempSB.toString()) ;
    

    非常感谢kcopock发布您找到的解决方案。我已经找了几个小时了,这是我能找到的唯一一篇简洁明了的文章。我正在做的任务非常紧急,没有你的帮助我会失败的。

        2
  •  1
  •   Kevin Coppock    15 年前

    如果这对任何人都有帮助的话,我可以通过对数据感兴趣的每个字段使用布尔值来解决这个问题。然后我继续追加到一个StringBuilder,直到到达一个结束标记,之后我获取StringBuilder值,然后清空它,并将布尔值设置为false。

    @Override
        public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
            sb.delete(0, sb.length());
            if (localName.equalsIgnoreCase("channel")) {
                inChannel = true;
                newFeed = new Feed();
                itemList = new ArrayList<Item>();
            }
            if (inChannel) {            
                if (localName.equalsIgnoreCase("image")) {
                    feedImage = new Image();
                    inImage = true;
                    return;
                }           
                else if (localName.equalsIgnoreCase("item")) {
                    newItem = new Item();
                    inItem = true;
                    return;
                }
    
                if(inImage) { //set booleans for image elements
                    if (localName.equalsIgnoreCase("title")) imgTitle = true;
                    else if (localName.equalsIgnoreCase("link")) imgLink = true;
                    else if (localName.equalsIgnoreCase("url")) imgURL = true;
                    return;
                }           
                else if(inItem) { //set booleans for item elements
                    if (localName.equalsIgnoreCase("title")) iTitle = true;
                    else if (localName.equalsIgnoreCase("link")) iLink = true;
                    else if (localName.equalsIgnoreCase("description")) iDescription = true;
                    else if (localName.equalsIgnoreCase("author")) iAuthor = true;
                    else if (localName.equalsIgnoreCase("category")) iCategory = true;
                    else if (localName.equalsIgnoreCase("comments")) iComments = true;
                    else if (localName.equalsIgnoreCase("guid")) iGuid = true;
                    else if (localName.equalsIgnoreCase("pubdate")) iPubDate= true;
                    else if (localName.equalsIgnoreCase("source")) iSource = true;
                    return;
                } else { //set booleans for channel elements
                    if (localName.equalsIgnoreCase("title")) fTitle = true;
                    else if (localName.equalsIgnoreCase("link")) fLink = true;
                    else if (localName.equalsIgnoreCase("description")) fDescription = true;
                    else if (localName.equalsIgnoreCase("language")) fLanguage= true;
                    else if (localName.equalsIgnoreCase("copyright")) fCopyright = true;
                    else if (localName.equalsIgnoreCase("category")) fCategory = true;
                    return;
                }
            }       
        }
    
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if(inChannel) {
                if(inImage) {
                    if (localName.equalsIgnoreCase("title")) {
                        feedImage.setTitle(sb.toString());
                        sb.delete(0, sb.length());
                        imgTitle = false;
                        return;
                    }
                    else if (localName.equalsIgnoreCase("link")) {
                        feedImage.setLink(sb.toString());
                        sb.delete(0, sb.length());
                        imgLink = false;
                        return;
                    }
                    else if (localName.equalsIgnoreCase("url")) {
                        feedImage.setUrl(sb.toString());
                        sb.delete(0, sb.length());
                        imgURL = false;
                        return;
                    }
                    else return;
                } 
                else if(inItem) {
                    if (localName.equalsIgnoreCase("item")) {
                        itemList.add(newItem);
                        newItem = null;
                        inItem = false;
                        return;
                    } else if (localName.equalsIgnoreCase("title")) {
                        newItem.setTitle(sb.toString()); 
                        sb.delete(0, sb.length());
                        iTitle = false;
                        return;
                    } else if (localName.equalsIgnoreCase("link")) {
                        newItem.setLink(sb.toString()); 
                        sb.delete(0, sb.length());
                        iLink = false;
                        return;
                    } else if (localName.equalsIgnoreCase("description")) {
                        newItem.setDescription(sb.toString()); 
                        sb.delete(0, sb.length());
                        iDescription = false;
                        return;
                    } else if (localName.equalsIgnoreCase("author")) {
                        newItem.setAuthor(sb.toString()); 
                        sb.delete(0, sb.length());
                        iAuthor = false;
                        return;
                    } else if (localName.equalsIgnoreCase("category")) {
                        newItem.addCategory(sb.toString()); 
                        sb.delete(0, sb.length());
                        iCategory = false;
                        return;
                    } else if (localName.equalsIgnoreCase("comments")) {
                        newItem.setComments(sb.toString());
                        sb.delete(0, sb.length());
                        iComments = false;
                        return;
                    } /*else if (localName.equalsIgnoreCase("enclosure")) {
                         To be implemented later
                    }*/ else if (localName.equalsIgnoreCase("guid")) {
                        newItem.setGuid(sb.toString()); 
                        sb.delete(0, sb.length());
                        iGuid = false;
                        return;
                    } else if (localName.equalsIgnoreCase("pubDate")) {
                        newItem.setPubDate(sb.toString()); 
                        sb.delete(0, sb.length());
                        iPubDate = false;
                        return;
                    }
                } 
                else {
                    if(localName.equalsIgnoreCase("channel")) {
                        newFeed.setItems((ArrayList<Item>)itemList);
                        finalFeed = newFeed;
                        newFeed = null;                     
                        inChannel = false;
                        return;
                    } else if(localName.equalsIgnoreCase("title")) {
                        newFeed.setTitle(currentValue); 
                        sb.delete(0, sb.length());
                        fTitle = false;
                        return;
                    } else if(localName.equalsIgnoreCase("link")) {
                        newFeed.setLink(currentValue); 
                        sb.delete(0, sb.length());
                        fLink = false;
                        return;
                    } else if(localName.equalsIgnoreCase("description")) {
                        newFeed.setDescription(sb.toString());
                        sb.delete(0, sb.length());
                        fDescription = false;
                        return;
                    } else if(localName.equalsIgnoreCase("language")) {
                        newFeed.setLanguage(currentValue); 
                        sb.delete(0, sb.length());
                        fLanguage = false;
                        return;
                    } else if(localName.equalsIgnoreCase("copyright")) {
                        newFeed.setCopyright(currentValue); 
                        sb.delete(0, sb.length());
                        fCopyright = false;
                        return;
                    } else if(localName.equalsIgnoreCase("category")) {
                        newFeed.addCategory(currentValue); 
                        sb.delete(0, sb.length());
                        fCategory = false;
                        return;
                    }
                }
            }
        }
    
        @Override
        public void characters(char[] ch, int start, int length) {
            sb.append(new String(ch, start, length));
        }
    
        3
  •  0
  •   VNVN    15 年前

    像这样的特殊字符包含在CDATA标记中。您需要看到它们被保留下来,然后SAX解析器可以正确地处理它们。