如何使用排序的键将 java.util.Properties 写入 XML?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/54295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:52:01  来源:igfitidea点击:

How to write java.util.Properties to XML with sorted keys?

javaxml

提问by user5084

I'd like to store a properties file as XML. Is there a way to sort the keys when doing this so that the generated XML file will be in alphabetical order?

我想将属性文件存储为 XML。这样做时有没有办法对键进行排序,以便生成的 XML 文件按字母顺序排列?

String propFile = "/path/to/file";
Properties props = new Properties();
/*set some properties here*/
try {
    FileOutputStream xmlStream = new FileOutputStream(propFile);
    /*this comes out unsorted*/
    props.storeToXML(xmlStream,"");
} catch (IOException e) {
    e.printStackTrace();
}

回答by erickson

Here's a quick and dirty way to do it:

这是一种快速而肮脏的方法:

String propFile = "/path/to/file";
Properties props = new Properties();

/* Set some properties here */

Properties tmp = new Properties() {
  @Override
  public Set<Object> keySet() {
    return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
  }
};

tmp.putAll(props);

try {
    FileOutputStream xmlStream = new FileOutputStream(propFile);
    /* This comes out SORTED! */
    tmp.storeToXML(xmlStream,"");
} catch (IOException e) {
    e.printStackTrace();
}

Here are the caveats:

以下是注意事项:

  • The tmp Properties (an anonymous subclass) doesn't fulfill the contract of Properties.
  • tmp Properties(匿名子类)不履行 Properties 的契约。

For example, if you got its keySetand tried to remove an element from it, an exception would be raised. So, don't allow instances of this subclass to escape! In the snippet above, you are never passing it to another object or returning it to a caller who has a legitimate expectation that it fulfills the contract of Properties, so it is safe.

例如,如果您获得它keySet并试图从中删除一个元素,则会引发异常。所以,不要让这个子类的实例逃逸!在上面的代码片段中,你永远不会将它传递给另一个对象或将它返回给一个合法期望它满足属性合同的调用者,所以它是安全的。

  • The implementation of Properties.storeToXML could change, causing it to ignore the keySet method.
  • Properties.storeToXML 的实现可能会改变,导致它忽略 keySet 方法。

For example, a future release, or OpenJDK, could use the keys()method of Hashtableinstead of keySet. This is one of the reasons why classes should always document their "self-use" (Effective Java Item 15). However, in this case, the worst that would happen is that your output would revert to unsorted.

例如,未来的版本或 OpenJDK 可以使用keys()方法Hashtable代替keySet。这就是为什么类应该始终记录其“自用”(Effective Java Item 15)的原因之一。但是,在这种情况下,最糟糕的情况是您的输出将恢复为未排序。

  • Remember that the Properties storage methods ignore any "default" entries.
  • 请记住,属性存储方法会忽略任何“默认”条目。

回答by Espen

Here's a way to produce sorted output for both store Properties.store(OutputStream out, String comments)and Properties.storeToXML(OutputStream os, String comment):

这是一种为 storeProperties.store(OutputStream out, String comments)和生成排序输出的方法Properties.storeToXML(OutputStream os, String comment)

Properties props = new Properties() {
    @Override
    public Set<Object> keySet(){
        return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
    }

    @Override
    public synchronized Enumeration<Object> keys() {
        return Collections.enumeration(new TreeSet<Object>(super.keySet()));
    }
};
props.put("B", "Should come second");
props.put("A", "Should come first");
props.storeToXML(new FileOutputStream(new File("sortedProps.xml")), null);
props.store(new FileOutputStream(new File("sortedProps.properties")), null);

回答by Tom Hawtin - tackline

The simplest hack would be to override keySet. A bit of a hack, and not guaranteed to work in future implementations:

最简单的方法是覆盖 keySet。有点黑客,不能保证在未来的实现中工作:

new Properties() {
    @Override Set<Object> keySet() {
        return new TreeSet<Object>(super.keySet());
    }
}

(Disclaimer: I have not even tested that it compiles.)

(免责声明:我什至没有测试过它可以编译。)

Alternatively, you could use something like XSLT to reformat the produced XML.

或者,您可以使用 XSLT 之类的东西来重新格式化生成的 XML。

回答by ScArcher2

You could sort the keys first, then loop through the items in the properties file and write them to the xml file.

您可以先对键进行排序,然后遍历属性文件中的项目并将它们写入 xml 文件。

public static void main(String[] args){
        String propFile = "/tmp/test2.xml";
        Properties props = new Properties();
        props.setProperty("key", "value");
        props.setProperty("key1", "value1");
        props.setProperty("key2", "value2");
        props.setProperty("key3", "value3");
        props.setProperty("key4", "value4");

        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(propFile));
            List<String> list = new ArrayList<String>();
            for(Object o : props.keySet()){
                list.add((String)o);
            }
            Collections.sort(list);
            out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
            out.write("<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n");
            out.write("<properties>\n");
            out.write("<comment/>\n");
            for(String s : list){
                out.write("<entry key=\"" + s + "\">" + props.getProperty(s) + "</entry>\n");
            }
            out.write("</properties>\n");
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

回答by samjudson

java.util.Properties is based on Hashtable, which does not store its values in alphabetical order, but in order of the hash of each item, that is why you are seeing the behaviour you are.

java.util.Properties 基于 Hashtable,它不按字母顺序存储其值,而是按每个项目的散列顺序存储,这就是您看到自己行为的原因。

回答by Stu Thompson

java.util.Properties is a subclass of java.util.Hashtable. ('Hash', being the key here.)You'd have to come up with your own customer implementation based on something that keeps/defines order...like a TreeMap.

java.util.Properties 是 java.util 的子类。哈希表。('Hash',是这里的关键。)你必须根据保持/定义顺序的东西提出你自己的客户实现......就像一个TreeMap。

回答by nnhthuan

You can implement your LinkedPropertieswhich is sorted instead of using the Propertiesof Java.

你可以实现你的LinkedPropertieswhich 是 sorted 而不是使用PropertiesJava 的。

The source code sample:

源代码示例:

package com.cpviet.training.eclipseplugin;

import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

public class LinkedProperties extends Properties {

    private static final long serialVersionUID = 1L;

    private Map<Object, Object> m_linkMap = new LinkedHashMap<Object, Object>();

    @Override
    public synchronized Object put(Object key, Object value) {
        return m_linkMap.put(key, value);
    }

    @Override
    public synchronized boolean contains(Object value) {
        return m_linkMap.containsValue(value);
    }

    @Override
    public boolean containsValue(Object value) {
        return m_linkMap.containsValue(value);
    }

    @Override
    public synchronized Enumeration<Object> elements() {
        throw new UnsupportedOperationException("Enumerations are so old-school, don't use them, " + "use keySet() or entrySet() instead");
    }

    @Override
    public Set<Entry<Object, Object>> entrySet() {
        return m_linkMap.entrySet();
    }

    @Override
    public synchronized void clear() {
        m_linkMap.clear();
    }

    @Override
    public synchronized boolean containsKey(Object key) {
        return m_linkMap.containsKey(key);
    }

}

回答by trevorsky

In my testing, the other answers to this question don't work properly on AIX. My particular test machine is running this version:

在我的测试中,这个问题的其他答案在 AIX 上不能正常工作。我的特定测试机器正在运行这个版本:

IBM J9 VM (build 2.4, JRE 1.6.0 IBM J9 2.4 AIX ppc64-64 jvmap6460sr9-20110624_85526

IBM J9 VM(构建 2.4,JRE 1.6.0 IBM J9 2.4 AIX ppc64-64 jvmap6460sr9-20110624_85526

After looking through the implementation of the storemethod, I found that it relies upon entrySet. This method works well for me.

在查看该store方法的实现后,我发现它依赖于entrySet. 这种方法对我很有效。

public static void saveSorted(Properties props, FileWriter fw, String comment) throws IOException {
    Properties tmp = new Properties() {
        @Override
        public Set<Object> keySet() {
            return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
        }

        @Override
        public Set<java.util.Map.Entry<Object,Object>> entrySet() {
            TreeSet<java.util.Map.Entry<Object,Object>> tmp = new TreeSet<java.util.Map.Entry<Object,Object>>(new Comparator<java.util.Map.Entry<Object,Object>>() {
                @Override
                public int compare(java.util.Map.Entry<Object, Object> entry1, java.util.Map.Entry<Object, Object> entry2) {
                    String key1 = entry1.getKey().toString();
                    String key2 = entry2.getKey().toString();
                    return key1.compareTo(key2);
                }
            });

            tmp.addAll(super.entrySet());

            return Collections.unmodifiableSet(tmp);
        }

        @Override
        public synchronized Enumeration<Object> keys() {
            return Collections.enumeration(new TreeSet<Object>(super.keySet()));
        }

        @Override
        public Set<String> stringPropertyNames() {
            TreeSet<String> set = new TreeSet<String>();
            for(Object o : keySet()) {
                set.add((String)o);
            }
            return set;
        }
    };

    tmp.putAll(props);
    tmp.store(fw, comment);
}

回答by Serg

Here is another solution:

这是另一个解决方案:

public static void save_sorted(Properties props, String filename) throws Throwable {
    FileOutputStream fos = new FileOutputStream(filename);
    Properties prop_sorted = new Properties() {
        @Override
        public Set<String> stringPropertyNames() {
            TreeSet<String> set = new TreeSet<String>();
            for (Object o : keySet()) {
                set.add((String) o);
            }
            return set;
        }
    };
    prop_sorted.putAll(props);
    prop_sorted.storeToXML(fos, "test xml");
}

回答by Jay R.

You could try this:

你可以试试这个:

Make a new class that does what java.util.XMLUtils does but in the save method change this:

创建一个新类来执行 java.util.XMLUtils 所做的事情,但在 save 方法中更改:

Set keys = props.keySet();
Iterator i = keys.iterator();

to

Set keys = props.keySet();
List<String> newKeys = new ArrayList<String>();
for(Object key : keys)
{
   newKeys.add(key.toString());
}
Collections.sort(newKeys);
Iterator i = newKeys.iterator();

Extend properties and override the Properties class storeToXML method to call your new class's save method.

扩展属性并覆盖 Properties 类的 storeToXML 方法以调用新类的 save 方法。