如何使用 Android 做一个简单的 XML 解析器

发布于 2024-12-14 13:22:43 字数 1844 浏览 1 评论 0原文

天哪,我已经被困在这个问题上有一段时间了。我知道这应该很简单,但我似乎找不到我哪里出错了。在遵循并尝试调整此处的 DOM 解析器示例后,我构建了我的小型 XML 解析器: http://www.ibm.com/developerworks/opensource/library/x-android/index.html 我让它识别节点,但我一生都无法弄清楚为什么这是告诉我节点的值为“null”。帮助将不胜感激。

我的 XML 测试文件。

<?xml version="1.0"?>
<Person>
    <Name>Scott</Name>
    <Gender>Male</Gender>
    <More>And So On..</More>
</Person>

我的解析器代码是。

public class XMLParser {
    InputStream xmlDocument;
    TextView tv;

    public XMLParser(InputStream xmlDocument, TextView tv) {
        this.xmlDocument = xmlDocument;
        this.tv = tv;
    }

    public HashMap<String, String> parse() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        HashMap<String, String> xmlItems = new HashMap<String, String>();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document dom = builder.parse(xmlDocument);
            Element root = dom.getDocumentElement();
            NodeList items = root.getElementsByTagName("Person");
            Element rootElement = (Element)items.item(0);
            items = rootElement.getChildNodes();
            tv.append("\nParser, # of Items: " + String.valueOf(items.getLength()));
            for (int i = 0; i < items.getLength(); i++){
                Node item = items.item(i);
                xmlItems.put(item.getNodeName(), item.getNodeValue());
                tv.append("\nNM: " + item.getNodeName() + " NV: " + item.getNodeValue());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } 
        return xmlItems;
    }
}

Hell there, I have been stuck on this for a bit now. I know it should be simple but I can't seem to find where I went wrong. I built my little XML parser after following and trying to adapt the DOM Parser example here: http://www.ibm.com/developerworks/opensource/library/x-android/index.html I have it recognising the nodes but I, for the life of me, can't figureout why it is telling me the value of the nodes is "null". Help would be greatly appreciated.

My XML test file.

<?xml version="1.0"?>
<Person>
    <Name>Scott</Name>
    <Gender>Male</Gender>
    <More>And So On..</More>
</Person>

My Parser code is.

public class XMLParser {
    InputStream xmlDocument;
    TextView tv;

    public XMLParser(InputStream xmlDocument, TextView tv) {
        this.xmlDocument = xmlDocument;
        this.tv = tv;
    }

    public HashMap<String, String> parse() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        HashMap<String, String> xmlItems = new HashMap<String, String>();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document dom = builder.parse(xmlDocument);
            Element root = dom.getDocumentElement();
            NodeList items = root.getElementsByTagName("Person");
            Element rootElement = (Element)items.item(0);
            items = rootElement.getChildNodes();
            tv.append("\nParser, # of Items: " + String.valueOf(items.getLength()));
            for (int i = 0; i < items.getLength(); i++){
                Node item = items.item(i);
                xmlItems.put(item.getNodeName(), item.getNodeValue());
                tv.append("\nNM: " + item.getNodeName() + " NV: " + item.getNodeValue());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } 
        return xmlItems;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

夏尔 2024-12-21 13:22:43

我正在使用 XmlPullFactory,它还不错。

编辑以转换为哈希图

请注意,实际上并不推荐这样做。此代码检查哈希图中的重复键,并且它将覆盖任何现有键!

public HashMap<String, String> parseXml(String xml) {
    XmlPullParserFactory factory;
    String tagName = "";
    String text = "";
            HashMap<String, String> hm = new HashMap<String, String>();
    
    try {
        factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XmlPullParser xpp = factory.newPullParser();
        StringReader sr = new StringReader(xml);
        xpp.setInput(sr);
        int eventType = xpp.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.TEXT) {
                text = xpp.getText(); //Pulling out node text
            } else if (eventType == XmlPullParser.END_TAG) {
                tagName = xpp.getName();
                hm.put(tagName, text);
                text = ""; //Reset text for the next node
            }
            eventType = xpp.next();
        }
    }  catch (XmlPullParserException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        Log.d("Exception attribute", e + "+" + tagName);
    }
}

I'm using XmlPullFactory, and it's not so bad.

Edit for Converting to Hashmap

Note that this isn't really recommended. This code does not check for duplicate keys in the hashmap, and it will overwrite any existing keys!!!

public HashMap<String, String> parseXml(String xml) {
    XmlPullParserFactory factory;
    String tagName = "";
    String text = "";
            HashMap<String, String> hm = new HashMap<String, String>();
    
    try {
        factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XmlPullParser xpp = factory.newPullParser();
        StringReader sr = new StringReader(xml);
        xpp.setInput(sr);
        int eventType = xpp.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.TEXT) {
                text = xpp.getText(); //Pulling out node text
            } else if (eventType == XmlPullParser.END_TAG) {
                tagName = xpp.getName();
                hm.put(tagName, text);
                text = ""; //Reset text for the next node
            }
            eventType = xpp.next();
        }
    }  catch (XmlPullParserException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        Log.d("Exception attribute", e + "+" + tagName);
    }
}
神妖 2024-12-21 13:22:43

看起来Person实际上是这里的根节点,也许你不需要root.getElementsByTagName("Person");

如果你计划有多个人可能将xml文件更改为然后更改它到 root.getElementsByTagName("Person");

It looks like Person is actually the root node here, maybe you don't need root.getElementsByTagName("Person");

If your planning on having multiple people maybe change the xml file to and then change it to root.getElementsByTagName("Person");

只想待在家 2024-12-21 13:22:43

也许可以从 IBM 示例转向一个更简单的示例,如下所示:
http://p-xr. com/android-tutorial-how-to-parseread-xml-data-into-android-listview/

Maybe move away from the IBM example to a simpler example like this one:
http://p-xr.com/android-tutorial-how-to-parseread-xml-data-into-android-listview/

迟到的我 2024-12-21 13:22:43

可以使用 SAX 解析器,例如:

private void parse(String xml) {
        final ArrayList<Person> people = new ArrayList<Person>();
        Xml.parse(xml, new DefaultHandler() {
            private Person person;
            private StringBuilder builder;

            @Override
            public void startElement(String uri, String localName,
                    String qName, Attributes attributes) throws SAXException {
                builder = new StringBuilder();
                if(localName.equals("Person")) {
                    person = new Person();
                }
            }

            @Override
            public void endElement(String uri, String localName, String qName)
                    throws SAXException {
                if(localName.equals("Person")) {
                    people.add(person);
                }
                else if(localName.equals("Name")){
                    person.setName(builder.toString());
                }
                else if(localName.equals...) {
                    ... etc
                }
            }

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

Could use a SAX parser something like:

private void parse(String xml) {
        final ArrayList<Person> people = new ArrayList<Person>();
        Xml.parse(xml, new DefaultHandler() {
            private Person person;
            private StringBuilder builder;

            @Override
            public void startElement(String uri, String localName,
                    String qName, Attributes attributes) throws SAXException {
                builder = new StringBuilder();
                if(localName.equals("Person")) {
                    person = new Person();
                }
            }

            @Override
            public void endElement(String uri, String localName, String qName)
                    throws SAXException {
                if(localName.equals("Person")) {
                    people.add(person);
                }
                else if(localName.equals("Name")){
                    person.setName(builder.toString());
                }
                else if(localName.equals...) {
                    ... etc
                }
            }

            @Override
            public void characters(char[] ch, int start, int length)
                    throws SAXException {
                builder.append(ch, start, length);
            }
        });
    }
最单纯的乌龟 2024-12-21 13:22:43

我发现 IBM 的示例笨重且混乱。我编写了自己的东西来处理 RSS 提要,它可以进行调整以适应自定义 XML 提要。

使用此示例:

此 yahoo feed 的内容保存到文件中并放置它在你的项目上。将文件读入字符串。

String fileContents = ...;
XMLFeed feed = XMLUtils.getXmlFeed(fileContents);

您现在有一个对象,其中包含 RSS 源中每个条目的列表

。下面有 4 个类。我为了自己的利益发表了一些评论,但可能会让其他人感到困惑。

基本上,DefaultHandler 会在 XML 字符串中查找常见的 RSS 名称,例如描述、URL、标题等。它将每个条目保存到自己的对象中,并将其添加到主列表中。可以更改 DefaultHandler 类中的常量(最终)字段(添加/删除字符串)以适合您的结构 - 尽管您可能需要更改 XmlFeedItem 类的结构也。

您应该能够在不更改标准 RSS 提要的情况下使用它。

希望有帮助

public class XMLUtils {
    public static XmlFeed getXmlFeed(String xmlString) {
        XMLHandler handler = null;
        try {
            XMLReader xr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();

            handler = new XMLHandler();
            xr.setContentHandler(handler);

            InputSource is = new InputSource();
            is.setEncoding("UTF-8");
            is.setCharacterStream(new StringReader(xmlString));

            xr.parse(is);
        }
        catch(SAXException e) {
            return null;
        }
        catch(ParserConfigurationException e) {
            return null;
        }
        catch(IOException e) {
            return null;
        }
        return handler.getXmlFeed();
    }
}

public class XMLHandler extends DefaultHandler {
    /**
     * entity names in the XML document such as <item> which contain many fields
     */
    private static final String OBJECTS[] = new String[] {"item", "entry"};

    /**
     * field names which correspond to a "description"
     */
    private static final String DESCRIPTIONS[] = new String[] {"description", "summary"};

    /**
     * field names which correspond to a "url"
     */
    private static final String URLS[] = new String[] {"link", "id", "guid"};

    /**
     * field names which correspond to "date"
     */
    private static final String PUB_DATES[] = new String[] {"pubDate", "date", "updated", "published", "timestamp"};

    /**
     * field names which correspond to "title"
     */
    private static final String TITLES[] = new String[] {"title"};

    /**
     * the current element being read in
     */
    private String currentElement;
    private boolean foundItem;
    private XmlFeed xmlFeed;
    private XmlFeedItem xmlFeedItem;

    private String object, description, url, pubDate, title;
    public XMLHandler() {
        currentElement = "";
        object = description = url = pubDate = title = null;
        foundItem = false;
        xmlFeed = new XmlFeed();
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        String s = new String(ch, start, length);
        if(foundItem && s.trim().length() > 0) {
            if(isFieldAvailable(currentElement, DESCRIPTIONS, description)) {
                xmlFeedItem.setDescription(xmlFeedItem.getDescription() + s);
            }
            else if(isFieldAvailable(currentElement, URLS, url)) {
                xmlFeedItem.setUrl(xmlFeedItem.getUrl() + s);
            }
            else if(isFieldAvailable(currentElement, PUB_DATES, pubDate)) {
                xmlFeedItem.setPubDate(xmlFeedItem.getPubDate() + s);
            }
            else if(isFieldAvailable(currentElement, TITLES, title)) {
                xmlFeedItem.setTitle(xmlFeedItem.getTitle() + s);
            }
        }
    }
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        if(isFieldAvailable(localName, OBJECTS, object)) {
            xmlFeed.getItems().add(new XmlFeedItem(xmlFeedItem));
            xmlFeedItem = new XmlFeedItem();
        }
    }
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }
    /**
     * @param fieldToTest the current element found in the XML string while parsing
     * @param options the array of elements available to match fieldToTest to
     * @param currentField the element that we're currently inside
     * @return <p>if <strong>fieldToTest</strong> is contained in <strong>options</strong> and if <strong>currentField</strong> 
     * is either null or contained in <strong>options</strong>.  This allows us to specify a number of different 
     * fields which mean the same thing in an XML feed.  Example: <strong>summary</strong> may not be included 
     * in a feed but <strong>description</strong> is.  Both <strong>summary</strong> and <strong>description</strong> are contained 
     * in the available <strong>options</strong>, so it is still matched up and used.  Once one element is used 
     * and is contained in <strong>options</strong> it will always use the same element.  <strong>currentField</strong> 
     * is assigned to <strong>fieldToTest</strong> if returning true and if its null(hasn't been matched before)</p>
     */
    private boolean isFieldAvailable(String fieldToTest, String[] options, String currentField) {
        for(String field: options) {
            if(field.equalsIgnoreCase(fieldToTest) && (currentField == null || currentField.equalsIgnoreCase(field))) {
                if(currentField == null) {
                    currentField = new String(fieldToTest);
                }
                return true;
            }
        }
        return false;
    }
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        currentElement = new String(localName);
        if(!foundItem && isFieldAvailable(localName, OBJECTS, object)) {
            foundItem = true;
            xmlFeedItem = new XmlFeedItem();
        }
    }
    public XmlFeed getXmlFeed() {
        return xmlFeed;
    }
}

public class XmlFeed {
    private List<XmlFeedItem> items;
    public XmlFeed() {
        items = new ArrayList<XmlFeedItem>();
    }
    public List<XmlFeedItem> getItems() {
        return items;
    }
    public void setItems(List<XmlFeedItem> items) {
        this.items = items;
    }
}

public class XmlFeedItem {
    private String title;
    private String description;
    private String pubDate;
    private String url;
    public XmlFeedItem() {
        title = description = pubDate = url = "";
    }
    public XmlFeedItem(XmlFeedItem rssFeedItem) {
        this.title = rssFeedItem.getTitle();
        this.description = rssFeedItem.getDescription();
        this.pubDate = rssFeedItem.getPubDate();
        this.url = rssFeedItem.getUrl();
    }
    public String getPubDate() {
        return pubDate;
    }
    public void setPubDate(String pubDate) {
        this.pubDate = pubDate;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
}

I found the IBM example clunky and messy. I wrote my own thing to handle RSS feeds, it can be adapted to accommodate custom XML feeds.

an example of using this:

save the contents of this yahoo feed into a file and place it on your project. read the file into a string.

String fileContents = ...;
XMLFeed feed = XMLUtils.getXmlFeed(fileContents);

you now have an object containing a list of each entry from the RSS feed

There are 4 classes below. I have commented some for my own good but it may be confusing for others.

Basically, the DefaultHandler looks through the XML string for common RSS names such as description, URL, title, etc. it saves each entry into its own object and adds it to the master list. the constant(final) fields in the DefaultHandler class can be changed(add/remove strings) to fit your structure - although you may need to change the structure of the XmlFeedItem class too.

You should be able to use this with no changes to standard RSS feeds.

hope it helps

public class XMLUtils {
    public static XmlFeed getXmlFeed(String xmlString) {
        XMLHandler handler = null;
        try {
            XMLReader xr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();

            handler = new XMLHandler();
            xr.setContentHandler(handler);

            InputSource is = new InputSource();
            is.setEncoding("UTF-8");
            is.setCharacterStream(new StringReader(xmlString));

            xr.parse(is);
        }
        catch(SAXException e) {
            return null;
        }
        catch(ParserConfigurationException e) {
            return null;
        }
        catch(IOException e) {
            return null;
        }
        return handler.getXmlFeed();
    }
}

public class XMLHandler extends DefaultHandler {
    /**
     * entity names in the XML document such as <item> which contain many fields
     */
    private static final String OBJECTS[] = new String[] {"item", "entry"};

    /**
     * field names which correspond to a "description"
     */
    private static final String DESCRIPTIONS[] = new String[] {"description", "summary"};

    /**
     * field names which correspond to a "url"
     */
    private static final String URLS[] = new String[] {"link", "id", "guid"};

    /**
     * field names which correspond to "date"
     */
    private static final String PUB_DATES[] = new String[] {"pubDate", "date", "updated", "published", "timestamp"};

    /**
     * field names which correspond to "title"
     */
    private static final String TITLES[] = new String[] {"title"};

    /**
     * the current element being read in
     */
    private String currentElement;
    private boolean foundItem;
    private XmlFeed xmlFeed;
    private XmlFeedItem xmlFeedItem;

    private String object, description, url, pubDate, title;
    public XMLHandler() {
        currentElement = "";
        object = description = url = pubDate = title = null;
        foundItem = false;
        xmlFeed = new XmlFeed();
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        String s = new String(ch, start, length);
        if(foundItem && s.trim().length() > 0) {
            if(isFieldAvailable(currentElement, DESCRIPTIONS, description)) {
                xmlFeedItem.setDescription(xmlFeedItem.getDescription() + s);
            }
            else if(isFieldAvailable(currentElement, URLS, url)) {
                xmlFeedItem.setUrl(xmlFeedItem.getUrl() + s);
            }
            else if(isFieldAvailable(currentElement, PUB_DATES, pubDate)) {
                xmlFeedItem.setPubDate(xmlFeedItem.getPubDate() + s);
            }
            else if(isFieldAvailable(currentElement, TITLES, title)) {
                xmlFeedItem.setTitle(xmlFeedItem.getTitle() + s);
            }
        }
    }
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        if(isFieldAvailable(localName, OBJECTS, object)) {
            xmlFeed.getItems().add(new XmlFeedItem(xmlFeedItem));
            xmlFeedItem = new XmlFeedItem();
        }
    }
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }
    /**
     * @param fieldToTest the current element found in the XML string while parsing
     * @param options the array of elements available to match fieldToTest to
     * @param currentField the element that we're currently inside
     * @return <p>if <strong>fieldToTest</strong> is contained in <strong>options</strong> and if <strong>currentField</strong> 
     * is either null or contained in <strong>options</strong>.  This allows us to specify a number of different 
     * fields which mean the same thing in an XML feed.  Example: <strong>summary</strong> may not be included 
     * in a feed but <strong>description</strong> is.  Both <strong>summary</strong> and <strong>description</strong> are contained 
     * in the available <strong>options</strong>, so it is still matched up and used.  Once one element is used 
     * and is contained in <strong>options</strong> it will always use the same element.  <strong>currentField</strong> 
     * is assigned to <strong>fieldToTest</strong> if returning true and if its null(hasn't been matched before)</p>
     */
    private boolean isFieldAvailable(String fieldToTest, String[] options, String currentField) {
        for(String field: options) {
            if(field.equalsIgnoreCase(fieldToTest) && (currentField == null || currentField.equalsIgnoreCase(field))) {
                if(currentField == null) {
                    currentField = new String(fieldToTest);
                }
                return true;
            }
        }
        return false;
    }
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        currentElement = new String(localName);
        if(!foundItem && isFieldAvailable(localName, OBJECTS, object)) {
            foundItem = true;
            xmlFeedItem = new XmlFeedItem();
        }
    }
    public XmlFeed getXmlFeed() {
        return xmlFeed;
    }
}

public class XmlFeed {
    private List<XmlFeedItem> items;
    public XmlFeed() {
        items = new ArrayList<XmlFeedItem>();
    }
    public List<XmlFeedItem> getItems() {
        return items;
    }
    public void setItems(List<XmlFeedItem> items) {
        this.items = items;
    }
}

public class XmlFeedItem {
    private String title;
    private String description;
    private String pubDate;
    private String url;
    public XmlFeedItem() {
        title = description = pubDate = url = "";
    }
    public XmlFeedItem(XmlFeedItem rssFeedItem) {
        this.title = rssFeedItem.getTitle();
        this.description = rssFeedItem.getDescription();
        this.pubDate = rssFeedItem.getPubDate();
        this.url = rssFeedItem.getUrl();
    }
    public String getPubDate() {
        return pubDate;
    }
    public void setPubDate(String pubDate) {
        this.pubDate = pubDate;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
}
萌逼全场 2024-12-21 13:22:43

Stax/pull 确实很笨重,因为 API 级别相当低并且很难直接使用。请尝试 Konsume-XML

val file = File("person.xml")
file.konsumeXml().use { k ->
    k.child("Person") {
        println(childText("Name"))
        println(childText("Gender"))
        println(childText("More"))
    }
}

这将打印

Scott
Male
And So On..

The Stax/pull is really clunky since the API is pretty low-level and hard to use directly. Please try Konsume-XML instead:

val file = File("person.xml")
file.konsumeXml().use { k ->
    k.child("Person") {
        println(childText("Name"))
        println(childText("Gender"))
        println(childText("More"))
    }
}

This will print

Scott
Male
And So On..
影子的影子 2024-12-21 13:22:43

我分享是因为我没有找到关于这个答案的好的代码,并且我不会向我的项目添加另一个外部库,所以我做了一个简单的 XML 解析器来转换 XML ->列表
显然,通过使用这个概念,任何人都可以做出比这个更好的实现,哈哈,

我在 PhP 中做了另一个 XML 解析器,它只使用对象(php 在创建动态对象方面更自由。)如果有人需要,只需在上面写一条评论,我会分享它。

XML 解析递归函数来解析完整修剪的 XML 字符串(XML 标签之间没有空格,并且没有 \n 和 \t)并获取 HashMap 树列表(HashMap 树是一个 HashMap,它可以包含其他 HashMap,它可以包含其他 HashMap ecc埃克,
所以在代码中:
HashMap,其中 T 可以是 HashMap,或者例如 String
所以
HashMap>>

用法:

DataUtils.parseStringXML(XML.replaceAll("[\\n\\t ]*", "")));

库代码:

(# LoL 于 10/07/2019 18:00 编辑 -> 添加“lastEvent”来管理空 XML 标签)

(# LoL 再次编辑 10/07/2019 18:52 -> 修复“lastEvent”管理空的 XML 标签)

/** XML Parsing Methods **/
public static <T extends Object> List<HashMap<String, T>> parseStringXML(String xml){
    List<HashMap<String, T>> ret = new ArrayList<>();
    if(xml != null && !TextUtils.isEmpty(xml)){
        try{
            XmlPullParserFactory xppFactory = XmlPullParserFactory.newInstance();
            xppFactory.setNamespaceAware(true);
            XmlPullParser xpp = xppFactory.newPullParser();
            xpp.setInput(new StringReader(xml));
            ret = parseTagsXML(xpp);
        } catch (XmlPullParserException xppE){
            EMaxLogger.onException(TAG, xppE);
        } catch (Exception e){
            EMaxLogger.onException(TAG, e);
        }
    }
    return ret;
}

/** XML Parsing Methods **/
private static <T extends Object> T parseTagsXML(XmlPullParser xpp) {
    int index = 0x0;
    List<HashMap<String, T>> tree = new ArrayList<HashMap<String, T>>(){{add(new HashMap<>());}};
    try{
        List<String> tags = new ArrayList<>();
        int event = 0x0; int lastEvent;
        while(event != XmlPullParser.END_DOCUMENT){
            lastEvent = xpp.getEventType();
            if(lastEvent == XmlPullParser.END_TAG && tags.contains(xpp.getName())){
                tags.remove(xpp.getName());
                if(tags.size() == 0x0){
                    return (T) new HashMap<String, T>(){{put(xpp.getName(), null);}};
                }
            }
            event = xpp.next();
            switch (event){
                case XmlPullParser.START_TAG:
                    tags.add(xpp.getName());
                    if(tags.size() >= 0x2 && containsStringKeyInMapsTree(tree.get(index), tags.get(tags.size() - 0x2))){
                        tree.set(index, putMapElementInTreeMaps(tags.get(tags.size() - 0x2), tree.get(index), tags.get(tags.size() - 0x1), parseTagsXML(xpp)));
                    } else {
                        tree.get(index).put(tags.get(tags.size() - 0x1), parseTagsXML(xpp));
                    }
                    break;
                case XmlPullParser.TEXT:
                    return (T) xpp.getText();
                case XmlPullParser.END_TAG:
                    if(tags.size() > 0x0 && tags.contains(xpp.getName())) {
                        tags.remove(xpp.getName());
                        if(tags.size() == 0x0){
                            if(xpp.getDepth() == 0x1) {
                                index++;
                                tree.add(new HashMap<>());
                                break;
                            } else {
                                return (T) tree.get(index);
                            }
                        }
                    }
                    if(lastEvent == XmlPullParser.START_TAG){
                        return null;
                    }
                    break;
            }
        }
        if(tree.size() >= index && (tree.get(index) == null || tree.get(index).isEmpty())) {
            tree.remove(index);
        }
    } catch(IOException ioE){
        EMaxLogger.onException(TAG, ioE);
    } catch(XmlPullParserException xppE){
        EMaxLogger.onException(TAG, xppE);
    }
    return (T) tree;
}

/** Tree HashMap Methods **/
private static <T extends Object> boolean containsStringKeyInMapsTree(HashMap<String, T> tree, String key) {
    if(tree != null){
        if(tree.containsKey(key)){
            return true;
        } else if(tree.size() > 0x0){
            for(String k : tree.keySet()){
                if(k != null && !TextUtils.isEmpty(k.trim()) && tree.get(k) != null && tree.get(k) instanceof HashMap && containsStringKeyInMapsTree((HashMap<String, T>) tree.get(k), key)){
                    return true;
                }
            }
        }
    }
    return false;
}

private static <T extends Object> HashMap<String, T> putMapElementInTreeMaps(String parentKey, HashMap<String, T> tree, String elementKey, T element){
    if(tree != null){
        if(tree.containsKey(parentKey) && tree.get(parentKey) != null && tree.get(parentKey) instanceof HashMap){
            ((HashMap<String, T>) tree.get(parentKey)).put(elementKey, element);
        } else if(tree.size() > 0x0){
            for(String key : tree.keySet()){
                if(key != null && !TextUtils.isEmpty(key.trim()) && tree.get(key) != null && tree.get(key) instanceof HashMap){
                    tree.put(key, (T) putMapElementInTreeMaps(parentKey, (HashMap<String, T>) tree.get(key), elementKey, element));
                }

            }
        }
    }
    return tree;
}

它使用递归。
也许如果我需要的话,我会做一个 XML 解析器,将 XML 转换为通用对象。
为此,您需要在对象中使用“预先确定”“setter 和 getter”方法。
例如,对于每个标记 XML,您将有一个“getTAG_NAME()”和一个“setTAG_NAME”方法,您将使用它们来设置对象内的值。

为此,您需要使用 Java - Field 和 Method 类,例如使用名称设置对象字段:

public static void setFieldValue(Object obj, Field field, int value){
    try {
        field.setInt(obj, value);
    } catch (IllegalAccessException iacE) {
        EMaxLogger.onException(TAG, iacE);
    } catch (IllegalArgumentException iarE) {
        EMaxLogger.onException(TAG, iarE);
    } catch (Exception e) {
        EMaxLogger.onException(TAG, e);
    }
}

因此,每次您有一个新的 XML_TAG 和一个新的 TAG_VALUE 时,您都可以通过以下方式调用相应的“setXML_TAG(TAG_VALUE)”方法 :使用上面的函数。

函数原型将类似于:

public static <T extends Object> T parseStringXmlToGenericObject(T myObj, String xml){ [...] }

其中 T 是为存储 XML 标签值而构建的特定对象,例如:

 <root_xml_tag>
      <xml_tag_0x1>lol</xml_tag_0x1> 
      <xml_tag_0x2>
           <xml_tag_0x2a>asd</xml_tag_0x2a>
           <xml_ag_0x2b>lmao</xml_tag_0x2b>
      </xml_tag_0x2>
      <xml_tag_0x3>rotfl</xml_tag_0x3>
 </root_xml_tag>

如果您有类似 xml 的内容,那么您存储 XML 数据的对象将是:

public class RootXmlTag {
  private String mXmlTag0x1;
  private XmlTag0x2 mXmlTag0x2;
  private String mXmlTag0x3;

  /** Setter & Getter Methods **/
  public void setxml_tag_0x1(String val){ 
     mXmlTag0x1 = val;
  }

  public String getxml_tag_0x1(){
     return mXmlTag0x1;
  }

  public void setxml_tag_0x2(XmlTag0x2 val){ 
     mXmlTag0x2 = val;
  }

  public XmlTag0x2 getxml_tag_0x2(){
     return mXmlTag0x2;
  }

  [... Ecc Ecc Setter & Getter Methods 4 Every Objects Properties ...]

  [... Other Methods you will need ....]


  /** Inner Classes For Parents XML Tags (Tags with Tags Sons ecc..) **/
  class XmlTag0x2 {

     private String mXmlTag0x2a;
     private String mXmlTag0x2b;

     /** Getter & Setter Methods **/
     [... See Outer Parent Class ...]
  }

}

那么当您获得 xml 标签时你只需做一个非常简单的例子(概念验证 [PoC):

// Assume having "T myObj" where T = RootXmlTag. 

String xmlTagName = xpp.getName();
event = xpp.next();
String tagValue = xpp.getText();
Utilities.setFieldValue(yourObj, "set".concat(xmlTagName), tagValue);

显然要做到这一点,你需要在解析 XML 之前知道它是怎样的(当你不知道的时候?哈哈。显然你会知道它是怎样的,也许你会有不同的版本带有不同标签的 xml,但你总是知道你将得到的结构。)

实际上我个人使用 HashMaps Trees 方式只是因为我不喜欢创建很多类来解析 2 或 3 个 XML,所以实际上我没有实现对象方式。如果我愿意这样做,我会分享它。

GG
再见,祝你编码愉快!

(我希望是否有人使用递归函数发布其他解决方案,只是为了比较和学习更多方法(:谢谢!再见)

I share because I didn't found good codes about this answer and I won't add another external library to my project so I did a simple XML Parser which converts XML -> List
Obviously by using the concept anyone can do a better implementation than this lol

I did another XML parser in PhP which only use objects (php is more free about creating customized on the fly objects.) if anyone need just write a comment above and I will share it.

XML parsing recursive functions to parse a Full Trimmed XML String (No space between XML Tags and no \n and \t) and get a List of HashMaps Tree (an HashMap tree is an HashMap which can contains others HashMaps which can contains others HashMaps ecc ecc,
so in code:
HashMap where T can be HashMap or, for example, String
so
HashMap>>

Usage:

DataUtils.parseStringXML(XML.replaceAll("[\\n\\t ]*", "")));

Library Code:

(# LoL Edited 10/07/2019 18:00 -> added "lastEvent" to manage empty XML tag)

(# LoL Edited Again 10/07/2019 18:52 -> fixed "lastEvent" to manage empty XML tags)

/** XML Parsing Methods **/
public static <T extends Object> List<HashMap<String, T>> parseStringXML(String xml){
    List<HashMap<String, T>> ret = new ArrayList<>();
    if(xml != null && !TextUtils.isEmpty(xml)){
        try{
            XmlPullParserFactory xppFactory = XmlPullParserFactory.newInstance();
            xppFactory.setNamespaceAware(true);
            XmlPullParser xpp = xppFactory.newPullParser();
            xpp.setInput(new StringReader(xml));
            ret = parseTagsXML(xpp);
        } catch (XmlPullParserException xppE){
            EMaxLogger.onException(TAG, xppE);
        } catch (Exception e){
            EMaxLogger.onException(TAG, e);
        }
    }
    return ret;
}

/** XML Parsing Methods **/
private static <T extends Object> T parseTagsXML(XmlPullParser xpp) {
    int index = 0x0;
    List<HashMap<String, T>> tree = new ArrayList<HashMap<String, T>>(){{add(new HashMap<>());}};
    try{
        List<String> tags = new ArrayList<>();
        int event = 0x0; int lastEvent;
        while(event != XmlPullParser.END_DOCUMENT){
            lastEvent = xpp.getEventType();
            if(lastEvent == XmlPullParser.END_TAG && tags.contains(xpp.getName())){
                tags.remove(xpp.getName());
                if(tags.size() == 0x0){
                    return (T) new HashMap<String, T>(){{put(xpp.getName(), null);}};
                }
            }
            event = xpp.next();
            switch (event){
                case XmlPullParser.START_TAG:
                    tags.add(xpp.getName());
                    if(tags.size() >= 0x2 && containsStringKeyInMapsTree(tree.get(index), tags.get(tags.size() - 0x2))){
                        tree.set(index, putMapElementInTreeMaps(tags.get(tags.size() - 0x2), tree.get(index), tags.get(tags.size() - 0x1), parseTagsXML(xpp)));
                    } else {
                        tree.get(index).put(tags.get(tags.size() - 0x1), parseTagsXML(xpp));
                    }
                    break;
                case XmlPullParser.TEXT:
                    return (T) xpp.getText();
                case XmlPullParser.END_TAG:
                    if(tags.size() > 0x0 && tags.contains(xpp.getName())) {
                        tags.remove(xpp.getName());
                        if(tags.size() == 0x0){
                            if(xpp.getDepth() == 0x1) {
                                index++;
                                tree.add(new HashMap<>());
                                break;
                            } else {
                                return (T) tree.get(index);
                            }
                        }
                    }
                    if(lastEvent == XmlPullParser.START_TAG){
                        return null;
                    }
                    break;
            }
        }
        if(tree.size() >= index && (tree.get(index) == null || tree.get(index).isEmpty())) {
            tree.remove(index);
        }
    } catch(IOException ioE){
        EMaxLogger.onException(TAG, ioE);
    } catch(XmlPullParserException xppE){
        EMaxLogger.onException(TAG, xppE);
    }
    return (T) tree;
}

/** Tree HashMap Methods **/
private static <T extends Object> boolean containsStringKeyInMapsTree(HashMap<String, T> tree, String key) {
    if(tree != null){
        if(tree.containsKey(key)){
            return true;
        } else if(tree.size() > 0x0){
            for(String k : tree.keySet()){
                if(k != null && !TextUtils.isEmpty(k.trim()) && tree.get(k) != null && tree.get(k) instanceof HashMap && containsStringKeyInMapsTree((HashMap<String, T>) tree.get(k), key)){
                    return true;
                }
            }
        }
    }
    return false;
}

private static <T extends Object> HashMap<String, T> putMapElementInTreeMaps(String parentKey, HashMap<String, T> tree, String elementKey, T element){
    if(tree != null){
        if(tree.containsKey(parentKey) && tree.get(parentKey) != null && tree.get(parentKey) instanceof HashMap){
            ((HashMap<String, T>) tree.get(parentKey)).put(elementKey, element);
        } else if(tree.size() > 0x0){
            for(String key : tree.keySet()){
                if(key != null && !TextUtils.isEmpty(key.trim()) && tree.get(key) != null && tree.get(key) instanceof HashMap){
                    tree.put(key, (T) putMapElementInTreeMaps(parentKey, (HashMap<String, T>) tree.get(key), elementKey, element));
                }

            }
        }
    }
    return tree;
}

It uses recursion.
Maybe if I need I will do an XML parser which converts XML to Generic Objects.
To do that you need to use "pre-determinate" "setter & getter" methods in the Object.
For example for every tag XML you will have a "getTAG_NAME()" and a "setTAG_NAME" method which you will use to set the value inside the object.

To do that you need to use Java - Field and Method classes, for example to set a Object field using is name:

public static void setFieldValue(Object obj, Field field, int value){
    try {
        field.setInt(obj, value);
    } catch (IllegalAccessException iacE) {
        EMaxLogger.onException(TAG, iacE);
    } catch (IllegalArgumentException iarE) {
        EMaxLogger.onException(TAG, iarE);
    } catch (Exception e) {
        EMaxLogger.onException(TAG, e);
    }
}

So every time you have a new XML_TAG and a new TAG_VALUE then you call the respective "setXML_TAG(TAG_VALUE)" method by using the function above.

The function prototype will be something like:

public static <T extends Object> T parseStringXmlToGenericObject(T myObj, String xml){ [...] }

Where T is the specific object built to store the XML TAGs Value, for example:

 <root_xml_tag>
      <xml_tag_0x1>lol</xml_tag_0x1> 
      <xml_tag_0x2>
           <xml_tag_0x2a>asd</xml_tag_0x2a>
           <xml_ag_0x2b>lmao</xml_tag_0x2b>
      </xml_tag_0x2>
      <xml_tag_0x3>rotfl</xml_tag_0x3>
 </root_xml_tag>

If you have anything like the xml Above your object to store XML data will be:

public class RootXmlTag {
  private String mXmlTag0x1;
  private XmlTag0x2 mXmlTag0x2;
  private String mXmlTag0x3;

  /** Setter & Getter Methods **/
  public void setxml_tag_0x1(String val){ 
     mXmlTag0x1 = val;
  }

  public String getxml_tag_0x1(){
     return mXmlTag0x1;
  }

  public void setxml_tag_0x2(XmlTag0x2 val){ 
     mXmlTag0x2 = val;
  }

  public XmlTag0x2 getxml_tag_0x2(){
     return mXmlTag0x2;
  }

  [... Ecc Ecc Setter & Getter Methods 4 Every Objects Properties ...]

  [... Other Methods you will need ....]


  /** Inner Classes For Parents XML Tags (Tags with Tags Sons ecc..) **/
  class XmlTag0x2 {

     private String mXmlTag0x2a;
     private String mXmlTag0x2b;

     /** Getter & Setter Methods **/
     [... See Outer Parent Class ...]
  }

}

So then when you get an xml tag you just do, really simple example (Proof-Of-Concept [PoC):

// Assume having "T myObj" where T = RootXmlTag. 

String xmlTagName = xpp.getName();
event = xpp.next();
String tagValue = xpp.getText();
Utilities.setFieldValue(yourObj, "set".concat(xmlTagName), tagValue);

Obviously to do that you need to know how the XML is before parse it (when you won't know that? lol. Obviously you will know how it is, maybe you will have different versions of the xml with differents tags, but you will always know the structure you will get.)

Personally actually I'm using the HashMaps Trees way just because I don't like to create a lot of class just to parse 2 or 3 XMLs, so actually I didn't implemented the Object Way. If I will do that I will share it.

GG
Bye, have a Nice Coding!

(I'd like if anybody post others solution using recursive functions just to compare and learn more methods (: Thank you! bye all)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文