По сути, у меня есть приложение для проверки концепции, которое представляет собой цифровую книгу рецептов. Каждый рецепт является объектом, и каждый объект имеет, помимо других полей, вектор, содержащий массивы. Вектор — это список всех ингредиентов в рецепте, в то время как каждый ингредиент имеет массив, показывающий название ингредиента, количество и единицу измерения этого количества. Я хочу сохранить каждый рецепт в XML, чтобы пользователь мог получить к ним доступ. Как я могу сохранить вектор массивов строк в XML или любом другом файле, чтобы его можно было позже вызвать и получить к нему доступ?
Java: Как сохранить Vector‹String[]› в XML (или сохранить любым другим способом)
Ответы (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% программы.
Даже для «быстрого» доказательства концепции экономия времени за счет использования действительно описательной структуры данных может быть значительной; поскольку доказательство концепции может быстро стать начальным прототипом, который затем может стать основой для реального выпуска.
Удачи и удачного программирования!
Почему бы не смоделировать ингредиент как реальный объект? Затем у вас есть последовательность элементов Ingredient в разделе Recipe, каждый из которых имеет свои собственные подэлементы или атрибуты имени, количества, единицы измерения и т. д.
Чтобы быстро начать работу, вы можете использовать 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>