在那里,我现在已经坚持了一下。我知道它应该很简单,但我似乎无法找到出错的地方。我在跟踪并尝试在此处调整DOM Parser示例后构建了我的小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>
My Parser代码是。
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;
}
}
答案 0 :(得分:1)
我正在使用XmlPullFactory,而且 不好。
编辑转换为Hashmap
请注意,这并不是真的值得推荐的。此代码执行不检查hashmap中的重复键,它将覆盖任何现有键!!!
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);
}
}
答案 1 :(得分:0)
看起来Person实际上是这里的根节点,也许你不需要root.getElementsByTagName("Person");
如果您计划拥有多个人可能会将xml文件更改为,然后将其更改为root.getElementsByTagName("Person");
答案 2 :(得分:0)
也许从IBM示例转移到像这样的简单示例: http://p-xr.com/android-tutorial-how-to-parseread-xml-data-into-android-listview/
答案 3 :(得分:0)
我发现IBM的例子很笨拙而且很乱。我编写了自己的东西来处理RSS提要,它可以适应自定义XML提要。
使用此示例:
将this 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;
}
}
答案 4 :(得分:0)
可以使用类似的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);
}
});
}
答案 5 :(得分:0)
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..
答案 6 :(得分:0)
我分享是因为我没有找到关于此答案的好的代码,也不会在项目中添加其他外部库,所以我做了一个简单的XML解析器,它可以转换XML->列表 显然,通过使用这种概念,任何人都可以比这种大声笑更好地实现
我在PhP中做了另一个XML解析器,该解析器仅使用对象(如果有人只需要在上面写注释,我会分享它。php对于在运行中创建自定义对象,php更为自由。)
XML解析递归函数,以解析完整修剪的XML字符串(XML标记之间没有空格,并且\ n和\ t之间没有空格),并获取HashMaps树列表(HashMap树是HashMap,其中可以包含其他HashMaps,该HashMaps可以包含其他HashMaps ecc ecc, 所以在代码中: HashMap,其中T可以是HashMap或例如String 所以 哈希图>>
用法:
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类,例如,使用名称设置Object字段:
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 TAG值的特定对象,例如:
<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的样子(当您不知道它时呢?大声笑。显然,您会知道它的样子,也许您会使用不同的XML版本标记,但您将永远知道所得到的结构。)
我个人实际上实际上是使用HashMaps Trees的方式,只是因为我不想创建很多仅用于解析2或3个XML的类,所以实际上我没有实现对象方式。如果愿意,我会分享。
GG 再见,编码不错!
(我想如果有人使用递归函数发布其他解决方案,只是为了比较和学习更多方法(:谢谢!再见)