简体   繁体   English

使用 SAX Parser 获取特定的子节点

[英]Fetch a particular child node using SAX Parser

emphasized text I have the following xml:强调文字我有以下xml:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
    <title>Game Analysis</title>
    <item>
        <title>Game</title>
        <description>ABC</description>
        <releaseDate>Sat, 21 Feb 2012 05:18:23 GMT</releaseDate>       
    </item>
    <item>
        <title>CoD</title>
        <description>XYZ</description>
        <releaseDate>Sat, 21 Feb 2011 05:18:23 GMT</releaseDate>            
    </item>
</channel>
</rss>

I have to parse this xml and fetch all the childNodes under 'item' and then check if it contains 'releaseDate' node or not.我必须解析这个 xml 并获取“item”下的所有子节点,然后检查它是否包含“releaseDate”节点。 if not then i have to throw an exception.如果不是,那么我必须抛出一个异常。

I have tried using xpath also but it was not working.我也尝试过使用 xpath 但它不起作用。

    XPathFactory xPathfactory = XPathFactory.newInstance();
    XPath xpath = xPathfactory.newXPath();
    XPathExpression expr = xpath.compile("//channel/item");

    Object result = expr.evaluate(document, XPathConstants.NODESET);
    NodeList nodes = (NodeList) result;
    for (int i = 0; i < nodes.getLength(); i++) {
        System.out.println(nodes.item(i).getChildNodes());
    }

Try this code.试试这个代码。 Don't forget to include SAX parser library in your project and remove rss-string from XML-document (hope this is accepted).不要忘记在您的项目中包含 SAX 解析器库并从 XML 文档中删除 rss-string(希望这被接受)。

public class SaxParserTest {
    public static void main(String... argv) {
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        try {
            SAXParser saxParser = saxParserFactory.newSAXParser();
            MyHandler handler = new MyHandler();
            saxParser.parse(new File("your path to XML-file here"), handler);
            List<Item> items = handler.getChannel().getItems();
            // your check of item release dates here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyHandler extends DefaultHandler {
    private StringBuilder data = new StringBuilder();

    private Channel channel;

    private String itemTitle;
    private String itemDescription;
    private String itemReleaseDate;

    private boolean isItem;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (!qName.equals("rss")) {
            if (qName.equalsIgnoreCase("channel")) {
                channel = new Channel();
            } else if (qName.equalsIgnoreCase("item")) {
                isItem = true;
            }
            data.setLength(0);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (qName.equalsIgnoreCase("title")) {
            if (!isItem) {
                channel.setTitle(data.toString());
            } else {
                itemTitle = data.toString();
            }
        } else if (qName.equalsIgnoreCase("item")) {
            channel.addItem(new Item(itemTitle, itemDescription, itemReleaseDate));
            itemTitle = null;
            itemDescription = null;
            itemReleaseDate = null;
            isItem = false;
        } else if (qName.equalsIgnoreCase("description")) {
            itemDescription = data.toString();
        } else if (qName.equalsIgnoreCase("releaseDate")) {
            itemReleaseDate = data.toString();
        }
    }

    @Override
    public void characters(char ch[], int start, int length) throws SAXException {
        data.append(new String(ch, start, length));
    }

    public Channel getChannel() {
        return channel;
    }
}

class Channel {
    private String title;
    private List<Item> items;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<Item> getItems() {
        return items;
    }

    public void setItems(List<Item> items) {
        this.items = items;
    }

    public void addItem(Item item) {
        if (items == null) {
            items = new ArrayList<Item>();
        }
        items.add(item);
    }
}

class Item {
    private String title;
    private String description;
    private String releaseDate;

    public Item(String title, String description, String releaseDate) {
        this.title = title;
        this.description = description;
        this.releaseDate = releaseDate;
    }
    public String getReleaseDate() {
        return releaseDate;
    }
}

XPath should work fine and could even be used to create a shorter solution. XPath 应该可以正常工作,甚至可以用于创建更短的解决方案。 The expression //channel/item[not(releaseDate)] will return all item nodes that does not have a releaseDate child node.表达式//channel/item[not(releaseDate)]将返回所有没有releaseDate子节点的item节点。 So this code should give you the answer:所以这段代码应该会给你答案:

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);

    Document document = dbf
            .newDocumentBuilder()
            .parse(...);

    XPath xpath = XPathFactory
            .newInstance()
            .newXPath();

    NodeList list = (NodeList) xpath.evaluate("//channel/item[not(releaseDate)]", document, XPathConstants.NODESET);
    if (list.getLength() != 0) {
        throw new Exception("Found <item> without <releaseDate>");
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM