【问题标题】:Advice for Simplifying code to Load an XML file?关于简化代码以加载 XML 文件的建议?
【发布时间】:2011-12-21 14:57:14
【问题描述】:

我终于完成了我的 XML 解析代码,现在看着它,吓到我了。此代码适用于基于 Android 的简单文本冒险游戏。

我的所有关于遭遇、位置和角色的数据都存储在“res”文件夹中的 XML 文件中。

我编写了这个 XML 解析器来遍历 XML 文件并将数据存储到一个名为 Encounter 的类中。然后,我可以在代码中的任何位置访问 Encounter 中的数据。

所以我想我把 OOP 部分搞定了。但是实际的解析看起来很乱。

有没有更好的方法来解析 XML 数据?

这是我的代码:

public class XmlParser extends Activity  {

private String xmlValue;
private int encounterID;
Encounter encounter;

public XmlParser()
    throws XmlPullParserException, IOException
{
    XmlPullParser xpp = getResources().getXml(R.xml.encounters);

    int eventType = xpp.getEventType();
    while (eventType != XmlPullParser.END_DOCUMENT) {
     String elName = xpp.getName();
     if(eventType == XmlPullParser.START_TAG) {     //creature
         eventType = xpp.next();

         //top level nodes
         if(xpp.getName().equalsIgnoreCase("identity")){
             eventType = xpp.next();
             if(elName.equalsIgnoreCase("name")) {
                 encounter.name = xpp.getText();
             } else if(elName.equalsIgnoreCase("race")) {
                 encounter.race = xpp.getText();
             } else if(elName.equalsIgnoreCase("gender")) {
                 encounter.gender = xpp.getText();
             } else if(elName.equalsIgnoreCase("alignment")) {
                 encounter.alignment = xpp.getText();
             } else if(elName.equalsIgnoreCase("age")) {
                 try {
                     encounter.age = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }
             }
         } else if (xpp.getName().equalsIgnoreCase("appearance")) {
             eventType = xpp.next();
             if(elName.equalsIgnoreCase("condition")){
                 encounter.condition = xpp.getText();
             } else if(elName.equalsIgnoreCase("skinColor")) {
                 encounter.skinColor = xpp.getText();
             } else if(elName.equalsIgnoreCase("hairColor")) {
                 encounter.hairColor = xpp.getText();
             } else if(elName.equalsIgnoreCase("size")) {
                 encounter.size = xpp.getText();
             } else if(elName.equalsIgnoreCase("height")) {
                 encounter.height = xpp.getText();
             } else if(elName.equalsIgnoreCase("weight")) {
                 encounter.weight = xpp.getText();
             }

         } else if (xpp.getName().equalsIgnoreCase("stats")) {
             eventType = xpp.next();
             if(elName.equalsIgnoreCase("hitPoints")) {
                 try {
                     encounter.HP = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }
             } else if(elName.equalsIgnoreCase("armorClass")) {
                 try {
                     encounter.AC = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }                   
             } else if(elName.equalsIgnoreCase("actionPoints")) {
                 try {
                     encounter.AP = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }                   
             } else if(elName.equalsIgnoreCase("magicPoint")) {
                 try {
                     encounter.AP = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }                   
             } else if(elName.equalsIgnoreCase("strength")) {
                 try {
                     encounter.strength = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }                   
             } else if(elName.equalsIgnoreCase("dexterity")) {
                 try {
                     encounter.dexterity = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }
             } else if(elName.equalsIgnoreCase("intelligence")) {
                 try {
                     encounter.intelligence = Integer.parseInt(xpp.getText());
                 } catch (NumberFormatException e) {
                     //ok
                 }
             }

         } else if (xpp.getName().equalsIgnoreCase("inventory")) {
             eventType = xpp.next();
             if(elName.equalsIgnoreCase("weapon")) {
                 encounter.weapon = xpp.getText();
             } else if(elName.equalsIgnoreCase("armor")) {
                 encounter.armor = xpp.getText();
             } else if(elName.equalsIgnoreCase("magicItem")) {
                 encounter.magicItem = xpp.getText();
             }

         } else if (xpp.getName().equalsIgnoreCase("magic")) {
            eventType = xpp.next();
            if(elName.equalsIgnoreCase("attackSpell")) {
                encounter.attackSpell = xpp.getText();
            } else if(elName.equalsIgnoreCase("defenseSpell")) {
                encounter.defenseSpell = xpp.getText();
            }
         } else if (xpp.getName().equalsIgnoreCase("treasureItems")) {
             eventType = xpp.next();
             if(elName.equalsIgnoreCase("item1")) {
                 encounter.item1 = xpp.getText();
             } else if(elName.equalsIgnoreCase("item2")) {
                 encounter.item2 = xpp.getText();
             }
         }
     } else if(eventType == XmlPullParser.END_TAG) {
         //System.out.println("End tag "+xpp.getName());
     }
     eventType = xpp.next();
    }
    //System.out.println("End document");
}

如果有人感兴趣,这里是我的 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<encounters>
<creature id="1" type="monster">
    <identity>
        <name></name>
        <race></race>
        <gender></gender>
        <age></age>
        <alignment></alignment>
    </identity>

    <appearance>
        <condition></condition>
        <skinColor></skinColor>
        <hairColor></hairColor>
        <size></size>
        <height></height>
        <weight></weight>
    </appearance>

    <stats>
        <hitPoints></hitPoints>
        <armorClass></armorClass>
        <actionPoints></actionPoints>
        <magicPoints></magicPoints>
        <strength></strength>
        <dexterity></dexterity>
        <intelligence></intelligence>
    </stats>

    <inventory>
        <weapon></weapon>
        <armor></armor>
        <magicItem></magicItem>
    </inventory>

    <magic>
        <attackSpell></attackSpell>
        <defenseSpell></defenseSpell>
    </magic>

    <treasureItems>
        <item1></item1>
        <item2></item2>
    </treasureItems>

</creature>

【问题讨论】:

  • 不是让代码不那么复杂的建议,但是您使用了大量的 try/catch 块,而没有使用它们抛出的异常。现在,如果您的代码的那部分出现任何问题,您甚至都不知道它出了问题。实际使用这些异常可能是个好主意,即使它只是打印堆栈跟踪。

标签: java android xml refactoring


【解决方案1】:

在处理具有直接对象映射的 XML 时,例如您的情况,我通常倾向于使用编组技术。现在最标准的是JAXB。但是,它会为您的应用程序增加相当多的开销(大约 9 兆),这在移动应用程序中是不可忽略的。在这种情况下,simple 等更轻量级的编组 API 可能会有一席之地。

【讨论】:

    【解决方案2】:

    您可以查看VTD-XML,轻量级库有效 非常适合 android(较大的也可以,但文件大小要大得多)。
    还有android自带的SAX-parser

    除此之外,当我使用 XmlPullParser 时,我通常有一个标签名作为键和整数的映射,然后我可以从映射中获取值,然后使用一个简单的开关,这会稍微清除代码:

    //Before parsing, or if used frequently the map can be put outside the method and reused:
    final HashMap<String, Integer> tags = new HashMap<String, Integer>(9, 1);
    tags.put("encounters", 0);
    tags.put("identity", 1);
    tags.put("name", 2);
    //And so on...
    
    //in your parse-loop:
    int tag = tags.get(xpp.getName());
    switch(tag){
    case 0: //Handle encounter tag...
    break;
    case 1: //Handle identity tag...
    break;
    case 2: //Handle name tag...
    break;
    //For all tags.
    }
    

    【讨论】:

    • 感谢您的 cmets。我认为 SAX 主要用于通过 URL 访问的 XML 文档。我的 XML 文档在手机上的“res”文件夹中。
    • 不客气,我从来没有真正使用过 sax,因为我一直发现 VTDXML 或 XmlPullParser 更适合我的需求。
    • 嗨 Jave - 你说“以标记名作为键的映射”是什么意思? ---谢谢
    • 谢谢...我想我明白了。所以你会先检查元素的名称?你会遍历 XML 文件吗? ---谢谢
    • 是的,这个开关就是去掉所有的 'else if' 和 equalsIgnoreCase(),所以本质上它是完全一样的,但是代码和比较更少。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-02
    相关资源
    最近更新 更多