Как написать java.util.Properties в XML с отсортированными ключами?
Я хотел бы сохранить файл свойств как 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();
}
Ответы
Ответ 1
Вот быстрый и грязный способ сделать это:
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();
}
Вот предостережения:
- Свойства TMP (анонимный
подкласс) не выполняет
договор о недвижимости.
Например, если вы получили keySet
и попытались удалить из него элемент, возникнет исключение. Так что не позволяйте экземплярам этого подкласса убегать! В приведенном выше фрагменте вы никогда не передадите его другому объекту или не передадите его вызывающей стороне, которая имеет законные основания полагать, что она выполняет контракт свойств, поэтому она безопасна.
- Реализация
Properties.storeToXML может измениться,
заставляя его игнорировать набор ключей
Метод.
Например, будущий выпуск, или OpenJDK, мог бы использовать метод keys()
Hashtable
вместо keySet
. Это одна из причин, по которой классы всегда должны документировать свое "самоиспользование" (Эффективный элемент Java 15). Однако в этом случае самое худшее, что может произойти, это то, что ваш вывод вернется к несортированному.
- Помните, что хранилище свойств
методы игнорируют любые "по умолчанию"
записей.
Ответ 2
Здесь вы можете создать отсортированный вывод для хранилища Properties.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);
Ответ 3
Самый простой взлом - это переопределить keySet. Немного взлома, и не гарантируется работа в будущих реализациях:
new Properties() {
@Override Set<Object> keySet() {
return new TreeSet<Object>(super.keySet());
}
}
(Отказ от ответственности: я даже не тестировал его компиляцию.)
В качестве альтернативы вы можете использовать что-то вроде XSLT для переформатирования созданного XML.
Ответ 4
Сначала вы можете сортировать ключи, а затем перебирать элементы в файле свойств и записывать их в 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();
}
}
Ответ 5
java.util.Properties основан на Hashtable, который не сохраняет свои значения в алфавитном порядке, а в порядке хэша каждого элемента, поэтому вы видите поведение, которое вы выполняете.
Ответ 6
java.util.Properties - это подкласс java.util. Hashtable. ( "Хеш", являясь ключевым здесь.) Вам придется придумать собственную реализацию клиента на основе того, что хранит/определяет порядок... как TreeMap.
Ответ 7
Вы можете реализовать свой LinkedProperties
, который сортируется вместо использования Properties
Java.
Пример исходного кода:
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);
}
}
Ответ 8
В моем тестировании другие ответы на этот вопрос не работают должным образом в AIX. Моя тестовая машина запускает эту версию:
IBM J9 VM (сборка 2.4, JRE 1.6.0 IBM J9 2.4 AIX ppc64-64 jvmap6460sr9-20110624_85526
Просматривая реализацию метода 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);
}
Ответ 9
Вы можете попробовать следующее:
Создайте новый класс, который делает то, что делает java.util.XMLUtils, но в методе сохранения это:
Set keys = props.keySet();
Iterator i = keys.iterator();
к
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();
Расширьте свойства и переопределите метод класса StoreToXML класса Properties, чтобы вызвать новый метод сохранения класса.
Ответ 10
Вот еще одно решение:
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");
}
Ответ 11
Почему вы хотите, чтобы XML файл был отсортирован в первую очередь? Предположительно, есть еще один фрагмент кода, который читает файл и помещает данные в другой объект Properties. Вы хотите сделать это, чтобы вручную находить и редактировать записи в файле XML?