Java: Как сохранить Vector‹String[]› в XML (или сохранить любым другим способом)

По сути, у меня есть приложение для проверки концепции, которое представляет собой цифровую книгу рецептов. Каждый рецепт является объектом, и каждый объект имеет, помимо других полей, вектор, содержащий массивы. Вектор — это список всех ингредиентов в рецепте, в то время как каждый ингредиент имеет массив, показывающий название ингредиента, количество и единицу измерения этого количества. Я хочу сохранить каждый рецепт в XML, чтобы пользователь мог получить к ним доступ. Как я могу сохранить вектор массивов строк в XML или любом другом файле, чтобы его можно было позже вызвать и получить к нему доступ?


person Sam Stern    schedule 26.04.2010    source источник
comment
Взгляните на java.sun.com/developer/technicalArticles/Programming/   -  person Searles    schedule 27.04.2010


Ответы (3)


Существует несколько методов генерации XML, каждый из которых имеет свои преимущества и недостатки. Проще всего реализовать (но сложнее всего правильно) создать XML вручную.

Предположим, вы хотите, чтобы ваш список ингредиентов выглядел примерно так:

<ingredients>
  <ingredient name="ginger"/>
  <ingredient name="cinnamon"/>
  <ingredient name="sugar"/>
</ingredients>

Вам нужен ваш код для обхода вектора:

System.out.println("<ingredients>");
Vector ingredients;
for (String name : ingredients) {
  System.out.print("  <ingredient name=\"");
  System.out.print(name);
  System.out.println("\"/>");
}
System.out.println("</ingredients>");

Проблема с таким методом заключается в том, что когда вы изменяете базовую структуру данных (в вашем случае вектор массивов), вам необходимо изменить код генерации XML для соответствия (что часто приводит к неправильному XML).

Гораздо лучше использовать XML-библиотеку для генерации XML. Хорошая библиотека XML всегда будет генерировать действительный XML.

import java.io.FileWriter;
import com.megginson.sax.XMLWriter;
import org.xml.sax.helpers.AttributesImpl;

public class GenerateXML
{

    public static void main (String args[])
    throws Exception
    {
    XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));

    writer.startDocument();
    writer.startElement("","ingredients","",null);
    for (String ingredient : ingredients) {
        AttributesImpl attribs = new AttributesImpl();
        attribs.addAttribute("","name","","",ingredient);
        writer.startElement("", "ingredient","",attribs);
        writer.endElement("ingredient");
    }
    writer.endElement("ingredients");
    writer.endDocument();
}

Более полное описание возможностей DOM XMLWriter см. на http://docstore.mik.ua/orelly/xml/sax2/ch02_02.htm с особым вниманием к разделу 2.2.3.

Вы также можете выполнить преобразование DOM в XML, но использование DOM означает, что вы должны создать DOM-представление вашей структуры данных, что, вероятно, (в вашем случае) является ненужным и нежелательным дополнительным шагом.

Кроме того, хотя вы можете начать с чего-то вроде векторных массивов строк, такая структура данных имеет мало общего с реальными представлениями о том, что влечет за собой рецепт. Возможно, в долгосрочной перспективе вам будет лучше использовать класс Recipie, который содержит классы для ингредиентов и инструкций (которые, в свою очередь, содержат шаги). Хотя может показаться, что на размещение трех или четырех различных типов классов требуется больше работы, эта предварительная работа экономит более чем в десять раз эквивалентный объем работы при выполнении последних 10% программы.

Даже для «быстрого» доказательства концепции экономия времени за счет использования действительно описательной структуры данных может быть значительной; поскольку доказательство концепции может быстро стать начальным прототипом, который затем может стать основой для реального выпуска.

Удачи и удачного программирования!

person Edwin Buck    schedule 27.04.2010

Почему бы не смоделировать ингредиент как реальный объект? Затем у вас есть последовательность элементов Ingredient в разделе Recipe, каждый из которых имеет свои собственные подэлементы или атрибуты имени, количества, единицы измерения и т. д.

person Colin Goudie    schedule 26.04.2010
comment
Из-за того, как я хочу, чтобы программа работала, вектор массивов реализовать намного проще. В основном из-за того, что я не знаю, сколько ингредиентов понадобится для каждого рецепта. В идеале я хотел бы получить ответ на этот вопрос, который не требует от меня изменения структуры моего приложения. - person Sam Stern; 27.04.2010
comment
Вы можете заставить схему xml принимать n количество ингредиентов, вам не нужно знать это заранее. На мой взгляд, кодирование реальных объектов домена внутри строк — это настоящий запах кода. - person Colin Goudie; 27.04.2010

Чтобы быстро начать работу, вы можете использовать XStream. По умолчанию он выдает хороший результат и очень гибок, так что вы можете получить практически то, что хотите, в XML.

Вы можете сериализовать объект в XML, написав

String xml = XStream.toXML(myObject);

Что касается структуры, вы можете продолжать использовать векторы и списки, когда заранее не знаете количество, но лучше использовать список объектов предметной области (рецепты, ингредиенты и т. д.), а не строковые массивы. С XStream вам не нужно превращать все в строку, чтобы получить ее в XML.

Если вы действительно хотите оставить все как есть без изменений, поведение XStream по умолчанию может не дать вам того, что вы хотите. Он не знает, какие строки являются рецептами, ингредиентами и т. д. В этом случае вам нужно написать немного больше. Например, этот код записывает Вектор, как рецепты с ингредиентами в файл «recipes.txt»:

Vector<String[]> recipes = ... (your vector of recipes)
PrettyPrintWriter writer = new PrettyPrintWriter(new FileWriter("recipes.txt"));
writer.startNode("recipes");
for (String[] recipe: recipes)
{
   writer.startNode("recipe");
   // you might write out attributes, such as the recipe name
   for (String ingredient: recipe)
   {
      writer.startNode("ingredient");
      writer.setValue(ingredient);
      writer.endNode();
   }
   writer.endNode();
}
writer.endNode();
writer.close();

Для вектора

Vector<String[]> v = new Vector<String[]>();
v.add("2 cups pasta", "1 onion");
v.add("2 eggs", "1.5 cups sugar", "1 tbsp butter");

вывод будет

<recipes>
   <recipe>
      <ingredient>2 cups pasta</ingredient>
      <ingredient>1 onion</ingredient>
   </recipe>
   <recipe>
      <ingredient>2 eggs</ingredient>
      <ingredient>1.5 cups sugar</ingredient>
      <ingredient>1 tbsp butter</ingredient>
   </recipe>
</recipes>
person mdma    schedule 27.04.2010