Jak napisać java.util.Properties do XML z posortowane klucze?

głosy
12

Chciałbym do przechowywania pliku właściwości jako XML. Czy istnieje sposób aby posortować klawiszy, gdy robi to tak, że wygenerowany plik XML będą w porządku alfabetycznym?

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();
}
Utwórz 10/09/2008 o 16:00
źródło użytkownik
W innych językach...                            


11 odpowiedzi

głosy
26

Oto szybki i brudny sposób to zrobić:

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();
}

Oto zastrzeżenia:

  • PZT Properties (podklasa anonimowy) nie wykonania umowy nieruchomości.

Na przykład, jeśli ma swoją keySeti starał się usunąć element z niego wyjątek zostanie podniesiony. Tak więc, nie pozwalają instancje tej podklasy uciec! W powyższym fragmencie, nigdy nie przechodzą go do innego obiektu lub odsyłając je do rozmówcy, który ma uzasadnione oczekiwanie, że spełnia umowę właściwości, więc jest bezpieczne.

  • Realizacja Properties.storeToXML może zmienić, powodując jej ignorować metodę Keyset.

Na przykład, przyszłość uwolnienie lub OpenJDK, można użyć keys()metody Hashtablezamiast keySet. Jest to jeden z powodów, dla klasy powinna zawsze udokumentować „self-use” (Skuteczne Java pkt 15). Jednak w tym przypadku, najgorsze, że stałoby się to, że wyjście będzie powrócić do sortowania.

  • Pamiętaj, że właściwości metody przechowywania ignorować żadnych „default” wpisy.
Odpowiedział 10/09/2008 o 16:41
źródło użytkownik

głosy
20

Oto sposób, aby produkować posortowaną wyjście zarówno dla sklepu Properties.store(OutputStream out, String comments)oraz 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);
Odpowiedział 15/07/2010 o 07:42
źródło użytkownik

głosy
3

Najprostszym Hack byłoby zastąpić Keyset. Trochę hack, a nie gwarantowane do pracy w przyszłych wdrożeń:

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

(Uwaga: nie mam jeszcze przetestowane, że kompiluje).

Alternatywnie, można użyć coś jak XSLT sformatować produkowanego XML.

Odpowiedział 10/09/2008 o 16:28
źródło użytkownik

głosy
2

Można sortować klucze pierwszy, następnie pętli elementów w pliku właściwości i zapisać je do pliku 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();
        }
    }
Odpowiedział 10/09/2008 o 16:06
źródło użytkownik

głosy
1

W moich testów, pozostałe odpowiedzi na to pytanie nie działają prawidłowo w systemie AIX. Moja szczególności maszyna test jest uruchomiony tej wersji:

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

Po pominie realizacji storemetody, stwierdziliśmy, że opiera się ona na entrySet. Ta metoda działa dobrze dla mnie.

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);
}
Odpowiedział 15/04/2014 o 19:56
źródło użytkownik

głosy
1

Można zaimplementować LinkedPropertiesktóra jest posortowana zamiast przy użyciu PropertiesJava.

Próbka kodu źródłowego:

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);
    }

}
Odpowiedział 10/05/2012 o 03:34
źródło użytkownik

głosy
1

java.util.Properties jest podklasą java.util. Hashtable . ( „Hash”, będący kluczem tutaj.) Trzeba wymyślić własnego wdrażania klienta w oparciu o coś, co trzyma / definiuje kolejność ... jak TreeMap.

Odpowiedział 10/09/2008 o 16:04
źródło użytkownik

głosy
1

java.util.Properties opiera się na Hashtable, który nie przechowuje swoje wartości w kolejności alfabetycznej, lecz w kolejności mieszania każdej pozycji, dlatego widzisz zachowanie jesteś.

Odpowiedział 10/09/2008 o 16:03
źródło użytkownik

głosy
0

Oto inne rozwiązanie:

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");
}
Odpowiedział 01/08/2013 o 00:12
źródło użytkownik

głosy
0

Można spróbować to:

Zrobić nową klasę, która robi to, co robi java.util.XMLUtils ale w sposobie zapisywania zmian to:

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

do

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();

Rozszerz właściwości i zastąpić Właściwości metody klasy storeToXML aby wywołać metodę swojej nowej klasy w oszczędzać.

Odpowiedział 10/09/2008 o 16:22
źródło użytkownik

głosy
-2

Dlaczego chcesz plik XML mają być sortowane w pierwszej kolejności? Można przypuszczać, że istnieje inny kawałek kodu, który odczytuje plik i umieszcza dane w innym obiekcie Właściwości. Chcesz zrobić to ręcznie, dzięki czemu można znaleźć i edytować wpisy w pliku XML?

Odpowiedział 10/09/2008 o 16:27
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more