Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
苹果pList格式的XML我可以通过Android Java解析它吗?_Java_Iphone_Android_Xml_Parsing - Fatal编程技术网

苹果pList格式的XML我可以通过Android Java解析它吗?

苹果pList格式的XML我可以通过Android Java解析它吗?,java,iphone,android,xml,parsing,Java,Iphone,Android,Xml,Parsing,我们可以在Android上从Java解析基于iPhone/iPad的pList XML吗? 请告诉我您是否使用过或知道任何此类库?由于plist只是一个XML文件,您可以使用任何可用的XML解析器。就我个人而言,我使用的是小文件。试试看 我现在正在测试 我编写了一个类来解析xml plist文件。它使用XmlPullParser进行解析。我只实现了我的项目需要的东西。但是,如果您需要比这个类提供的更多的东西,那么这应该可以让您开始扩展这个类 文件:XMLPropertyListConfigur

我们可以在Android上从Java解析基于iPhone/iPad的pList XML吗?
请告诉我您是否使用过或知道任何此类库?

由于plist只是一个XML文件,您可以使用任何可用的XML解析器。就我个人而言,我使用的是小文件。

试试看


我现在正在测试

我编写了一个类来解析xml plist文件。它使用XmlPullParser进行解析。我只实现了我的项目需要的东西。但是,如果您需要比这个类提供的更多的东西,那么这应该可以让您开始扩展这个类

文件:XMLPropertyListConfiguration.java


Akos的代码是imo迄今为止对这个问题的最佳回答。然而,他的算法不适用于嵌套数组,也不支持所有PList标记。我正在开发一个更通用的基于SAX的实现,用于Android中的PList解析。我将根据要求在我的博客上发布代码。

我承诺的PList解析器可以在以下位置找到:


玩得开心

这并不是您所要求的,但这是我所做的,而不是向我的项目中添加代码依赖项

您可以将PList文件转换为JSON文件并使用。OSX上有一个工具可以实现这一点,它是开发人员工具附带的(我认为,或者只是默认安装)


我已经试过了,但是这个库产生了非法参数错误,这已经在“已知问题”部分列出了。在测试过程中,您得到了什么?在你的机器上工作正常吗?或者请告诉我你是如何使它工作的。天啊,我也不能让它工作。最后,它工作了。我不得不做一些修正,不知道为什么上一次修改失败了。老实说,我没有太多时间去看发生了什么事。修复一些旧版本更容易。在android中使用xmlwise时有两件重要的事情:1)即使文件不是那么大(50k),它也非常慢2)在xmlwise.java第80行应该注释为://documentBuilderFactory.setAttribute(“,//loadExternalDTD);我相信我之前已经解决了这个问题,但是忘记了更新我发布到stackoverflow的代码。我刚刚更新了我帖子中的代码,以匹配我在本地拥有的最新副本。请再试一次。它现在应该支持嵌套数组了。@Akos Cz你能给我们一些例子来说明如何使用它吗?@AdamVarhegyi看看他在上面发布的答案;他给出了一个完整的例子。如何使用这个例子?我想不出如何恢复hashmap数据结构。这里的问题也是一样。你是如何从PList对象获取数据的?我想知道你是否有一个如何实现这个类的例子?Akos,你能给我们一些如何使用这个类的例子吗?当然。我已经用一个例子更新了上面的代码。@AkosCz您的类的授权是什么?它可以商业化使用吗?Apache许可证,2.0版是的,您可以根据许可证进行商业化使用。我必须在运行时这样做,因为作为回应,我得到了一个plist:(
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.example.plist;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Stack;

import org.xmlpull.v1.XmlPullParser;

import android.annotation.SuppressLint;
import android.util.Xml;

//import android.util.Log;

/**
 * This class will parse a plist xml file and store the contents in a
 * hierarchical HashMap of <String, Object> tuples, where the Object value could
 * be another HashMap, an ArrayList, Boolean, Date, String or Integer value.
 * 
 * Use the getConfiguration methods to retrieve the values from the parsed plist
 * file.
 * 
 * The key names for nested dictionary references must be of the form :
 * Dict1KeyName.Dict2KeyName.ElementKeyName
 * 
 * @author akoscz
 * 
 */

public class XMLPropertyListConfiguration {

    // private static final String TAG = "plist";

    /**
     * The nested (hierarchical) HashMap which holds our key-value pairs of our
     * plist file.
     */
    protected HashMap<String, Object> mPlistHashMap;

    /**
     * Constructor. Parse a plist file from the given InputStream.
     * 
     * @param inputStream
     *            The InputStream which has the bytes of the plist file we need
     *            to parse.
     */
    public XMLPropertyListConfiguration(InputStream inputStream) {
        mPlistHashMap = new HashMap<String, Object>();
        if (inputStream != null) {
            parse(inputStream);
        }
    }

    /**
     * Get an String configuration value for the given key.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @return The String value of the specified key.
     */
    public String getConfiguration(String keyName) {
        return (String) getConfigurationObject(keyName);
    }

    /**
     * Get a String configuration value for the given key. If there is no value
     * for the given key, then return the default value.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @param defaultValue
     *            The default value to return if they key has no associated
     *            value.
     * @return The String value of the specified key, or defaultValue if the
     *         value for keyName is null.
     */
    public String getConfigurationWithDefault(String keyName, String defaultValue) {
        String value = getConfiguration(keyName);
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * Get an Integer configuration value for the given key.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @return The Integer value of the specified key.
     */
    public Integer getConfigurationInteger(String keyName) {
        return (Integer) getConfigurationObject(keyName);
    }

    /**
     * Get an Integer configuration value for the given key. If there is no
     * value for the given key, then return the default value.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @param defaultValue
     *            The default value to return if they key has no associated
     *            value.
     * @return The Integer value of the specified key, or defaultValue if the
     *         value for keyName is null.
     */
    public Integer getConfigurationIntegerWithDefault(String keyName, Integer defaultValue) {
        Integer value = getConfigurationInteger(keyName);
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * Get a Date configuration value for the given key.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @return The Date value of the specified key.
     */
    public Date getConfigurationDate(String keyName) {
        return (Date) getConfigurationObject(keyName);
    }

    /**
     * Get a Date configuration value for the given key. If there is no value
     * for the given key, then return the default value.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @param defaultValue
     *            The default value to return if they key has no associated
     *            value.
     * @return The Date value of the specified key, or defaultValue if the value
     *         for keyName is null.
     */
    public Date getConfigurationDateWithDefault(String keyName, Date defaultValue) {
        Date value = getConfigurationDate(keyName);
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * Get a Boolean configuration value for the given key.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @return The Boolean value of the specified key.
     */
    public Boolean getConfigurationBoolean(String keyName) {
        return (Boolean) getConfigurationObject(keyName);
    }

    /**
     * Get a Boolean configuration value for the given key. If there is no
     * value for the given key, then return the default value.
     * 
     * @param keyName
     *            The name of the key to look up in the configuration
     *            dictionary.
     * @param defaultValue
     *            The default value to return if they key has no associated
     *            value.
     * @return The Boolean value of the specified key, or defaultValue if the
     *         value for keyName is null.
     */
    public Boolean getConfigurationBooleanWithDefault(String keyName,
            Boolean defaultValue) {
        Boolean value = getConfigurationBoolean(keyName);
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * Utility method which uses a XmlPullParser to iterate through the XML
     * elements and build up a hierarchical HashMap representing the key-value
     * pairs of the plist configuration file.
     * 
     * @param inputStream
     *            The InputStream which contains the plist XML file.
     */
    public void parse(InputStream inputStream) {
        mPlistHashMap.clear();
        XmlPullParser parser = Xml.newPullParser();

        try {
            parser.setInput(inputStream, null);

            int eventType = parser.getEventType();
            int arrayDepth = 0;

            boolean done = false;
            boolean parsingArray = false;

            String name = null;
            String key = null;

            Stack<HashMap<String, Object>> stack = new Stack<HashMap<String, Object>>();
            HashMap<String, Object> dict = null;
            ArrayList<Object> array = null;

            while (eventType != XmlPullParser.END_DOCUMENT && !done) {
                switch (eventType) {
                case XmlPullParser.START_DOCUMENT:
                    // Log.d(TAG, "START_DOCUMENT");
                    break;
                case XmlPullParser.START_TAG:
                    name = parser.getName();

                    if (name.equalsIgnoreCase("dict")) {
                        // root dict element
                        if (key == null) {
                            mPlistHashMap.clear();
                            dict = mPlistHashMap;
                        } else if (parsingArray) {
                            // Log.d(TAG, "START_TAG dict : inside array");
                            HashMap<String, Object> childDict = new HashMap<String, Object>();
                            array.add(childDict);
                            stack.push(dict);
                            dict = childDict;
                        } else {
                            // Log.d(TAG, "START_TAG dict : " + key);
                            HashMap<String, Object> childDict = new HashMap<String, Object>();
                            dict.put(key, childDict);
                            stack.push(dict);
                            dict = childDict;
                        }
                    } else if (name.equalsIgnoreCase("key")) {
                        key = parser.nextText();
                    } else if (name.equalsIgnoreCase("integer")) {
                        dict.put(key, Integer.valueOf(parser.nextText()));
                    } else if (name.equalsIgnoreCase("string")) {
                        if (parsingArray && (parser.getDepth() == (arrayDepth + 1))) {
                            array.add(parser.nextText());
                        } else {
                            dict.put(key, parser.nextText());
                        }
                    } else if (name.equalsIgnoreCase("array")) {
                        parsingArray = true;
                        array = new ArrayList<Object>();
                        dict.put(key, array);
                        arrayDepth = parser.getDepth();
                    } else if (name.equalsIgnoreCase("date")) {
                        dict.put(key, parseDate(parser.nextText()));
                    } else if (name.equalsIgnoreCase("true")) {
                        dict.put(key, Boolean.TRUE);
                    } else if (name.equalsIgnoreCase("false")) {
                        dict.put(key, Boolean.FALSE);
                    }
                    break;
                case XmlPullParser.END_TAG:
                    name = parser.getName();

                    if (name.equalsIgnoreCase("dict")) {
                        // Log.d(TAG, "END_TAG dict");
                        if (!stack.empty()) {
                            dict = stack.pop();
                        }
                    } else if (name.equalsIgnoreCase("array")) {
                        parsingArray = false;
                        array = null;
                    } else if (name.equalsIgnoreCase("plist")) {
                        done = true;
                    }

                    break;
                case XmlPullParser.END_DOCUMENT:
                    // Log.d(TAG, "END_DOCUMENT");
                    break;

                }
                eventType = parser.next();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Method to parse an ISO8601 string to a Date object.
     * http://www.java2s.com/Code/Java/Data-Type/ISO8601dateparsingutility.htm
     * 
     * @param input
     *            The ISO8601 date string
     * @return The Date object representing the ISO8601 date string.
     * @throws java.text.ParseException
     */
    @SuppressLint("SimpleDateFormat")
    public static Date parseDate(String input) throws java.text.ParseException {

        // NOTE: SimpleDateFormat uses GMT[-+]hh:mm for the TZ which breaks
        // things a bit. Before we go on we have to repair this.
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");

        // this is zero time so we need to add that TZ indicator for
        if (input.endsWith("Z")) {
            input = input.substring(0, input.length() - 1) + "GMT-00:00";
        } else {
            int inset = 6;

            String s0 = input.substring(0, input.length() - inset);
            String s1 = input.substring(input.length() - inset, input.length());

            input = s0 + "GMT" + s1;
        }

        return df.parse(input);
    }

    /**
     * Utility method which tokenizes the given keyName using the "." delimiter
     * and then looks up each token in the configuration dictionary. If the
     * token key points to a dictionary then it proceeds to the next token key
     * and looks up value of the token key in the dictionary it found from the
     * previous token key.
     * 
     * @param keyName
     *            The fully qualified key name.
     * @return The Object value associated with the given key, or null if the
     *         key does not exist.
     */
    @SuppressWarnings("unchecked")
    protected Object getConfigurationObject(String keyName) {
        String[] tokens = keyName.split("\\.");

        if (tokens.length > 1) {
            HashMap<String, Object> dict = mPlistHashMap;
            Object obj;
            for (int i = 0; i < tokens.length; i++) {
                obj = dict.get(tokens[i]);
                if (obj instanceof HashMap<?, ?>) {
                    dict = (HashMap<String, Object>) obj;
                    continue;
                }
                return obj;
            }
        }

        return mPlistHashMap.get(keyName);
    }
}
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.example.plist;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import android.util.Log;

public class ExamplePListParser extends XMLPropertyListConfiguration {
    private static final String TAG = "ExamplePListParser";

    public ExamplePListParser(InputStream inputStream) {
        super(inputStream);
    }

     public Integer getVersion() {
     return getConfigurationIntegerWithDefault("Version", 1);
     }

     public String getUrl() {
     return getConfigurationWithDefault("Url", "http://");
     }

     public Integer getBrowserVideoWidth(){
     return getConfigurationIntegerWithDefault("Browser.VideoWidth", 1280);
     }

     public Integer getBrowserVideoHeight(){
     return getConfigurationIntegerWithDefault("Browser.VideoHeight", 800);
     }

     public String getRating() {
     return getConfigurationWithDefault("Rating", "G");
     }

    public Date getExpireDate() {
        return getConfigurationDateWithDefault("ExpireDate", new Date());
    }

    public Boolean getHighRes() {
        return getConfigurationBooleanWithDefault("HighRes", Boolean.TRUE);
    }

    /**
     * Debug method. Print all the "dict" key names from our plist configuration
     * file
     */
    public void dumpKeys() {
        printHashKeys("root", mPlistHashMap);
    }

    /**
     * Debug method. Iterate through all the methods of this class and print our
     * the resulting values.
     */
    public void dumpValues() {

        try {
            Class<? extends XMLPropertyListConfiguration> c = this.getClass();
            Method m[] = c.getDeclaredMethods();
            for (int i = 0; i < m.length; i++) {
                // only invoke getter methods
                if (m[i].getName().startsWith("get")) {
                    // Log.d(TAG, m[i].getName());
                    if (m[i].getReturnType() == Integer.class) {
                        Log.d(TAG, m[i].getName() + " --> " + (Integer) m[i].invoke(this, (Object[]) null));
                    } else if (m[i].getReturnType() == ArrayList.class) {
                        Log.d(TAG, m[i].getName() + " --> Array");
                        dumpArrayList((ArrayList<?>) m[i].invoke(this, (Object[]) null));
                    } else if (m[i].getReturnType() == Date.class) {
                        Log.d(TAG, m[i].getName() + " --> " + (Date) m[i].invoke(this, (Object[]) null));
                    } else if (m[i].getReturnType() == Boolean.class) {
                        Log.d(TAG, m[i].getName() + " --> " + (Boolean) m[i].invoke(this, (Object[]) null));
                    } else if (m[i].getReturnType() == String.class) {
                        Log.d(TAG, m[i].getName() + " --> " + (String) m[i].invoke(this, (Object[]) null));
                    } else {
                        Log.d(TAG, m[i].getName() + " --> UNSUPPORTED TYPE");
                    }
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private void dumpArrayList(ArrayList<?> list) {
        for (Iterator<?> iter = list.iterator(); iter.hasNext();) {
            Object o = iter.next();
            if (o instanceof String) {
                Log.d(TAG, "\t" + (String) o);
            } else if (o instanceof Integer) {
                Log.d(TAG, "\t" + (Integer) o);
            } else if (o instanceof HashMap) {
                Log.d(TAG, "\tHashMap");
                @SuppressWarnings("unchecked")
                HashMap<String, Object> hash = (HashMap<String, Object>) o;
                for (Iterator<String> hashIter = hash.keySet().iterator(); hashIter.hasNext();) {
                    String key = hashIter.next();
                    Object value = hash.get(key);
                    if (value instanceof Integer) {
                        Log.d(TAG, "\t\t " + key + " = " + (Integer) value);
                    } else if (value instanceof String) {
                        Log.d(TAG, "\t\t " + key + " = " + (String) value);
                    }
                }
            }
        }
    }

    /**
     * Debug method. Iterate through all the keys in the HashMap (dict) and
     * print the key names for each child HashMap (dict).
     */
    @SuppressWarnings("unchecked")
    private void printHashKeys(String key, HashMap<String, Object> map) {
        Set<String> keys = map.keySet();
        Log.d(TAG, key + " --> " + keys.toString());
        for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
            key = iter.next();
            Object o = map.get(key);
            if (o instanceof HashMap) {
                printHashKeys(key, (HashMap<String, Object>) o);
            }
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Version</key>
        <integer>3</integer>
        <key>Url</key>
        <string>http://example.com/video.mp4</string>
        <key>ExpireDate</key>
        <date>2013-4-20T11:20:00Z</date>
        <key>HighRes</key>
        <false/>
        <key>Browser</key>
        <dict>
            <key>VideoWidth</key>
            <integer>640</integer>
            <key>VideoHeight</key>
            <integer>480</integer>
        </dict>
    </dict>
</plist>
ExamplePListParser mPListParser;
InputStream inputStream = new FileInputStream("/sdcard/sample.xml");

if(mPListParser == null) {
    mPListParser = new ExamplePListParser(inputStream);
} else {
    mPListParser.parse(inputStream);
}

int version = mPListParser.getVersion(); 
int height = mPListParser.getBrowserVideoHeight();
int width = mPListParser.getBrowserVideoWidth();
String url = mPListParser.getUrl();
String rating = mPListParser.getRating();
Date expireDate = mPListParser.getExpireDate();
boolean highRes = mPListParser.getHighRes();

// debug:  print out keys and values
mPListParser.dumpKeys();
mPListParser.dumpValues();
plutil -convert json Days.plist