Ваша ошибка в попытке декодировать один символ из ответа:
>>> snav_timetable[len(snav_timetable)-2]
'}'
Один символ не является документом JSON, поэтому по праву не удается выполнить синтаксический анализ. Вы хотите декодировать весь ответ :
snav_timetable_data = json.loads(snav_timetable)
Вы можете перейти к использованию библиотеки requests
, вместо этого здесь происходит загрузка Ответы JSON из тривиального API:
import requests
snav_timetable_data = requests.get(snav_timetable_url).json()
snav_timetable_data_cleaned = []
for departure in snav_timetable_data['data']['ratesOutward']:
snav_timetable_data_cleaned.append({
'COMPANY': 'Snav',
'CODICE CORSA': departure['coditinera'],
'DEPARTURE DATE TIME': departure['strDatapart'],
'ARRIVAL DATE TIME': departure['strDataarri']
})
Обратите внимание, что мне пришлось исправить опечатку в эталоне времени прибытия; это strDataarri
, а не strDatarri
.
Вам необходимо использовать метод включения XML.
Ваш error.xml (не изменяется, просто заглушка. Используется синтаксическими анализаторами XML для чтения) :
<?xml version="1.0"?>
<!DOCTYPE logfile [
<!ENTITY logrows
SYSTEM "errorrows.txt">
]>
<Errors>
&logrows;
</Errors>
Ваш файл errorrows.txt (изменяется, синтаксический анализатор xml его не понимает):
<Error>....</Error>
<Error>....</Error>
<Error>....</Error>
Затем, чтобы добавить запись в errorrows.txt:
using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
XmlTextWriter xtw = new XmlTextWriter(sw);
xtw.WriteStartElement("Error");
// ... write error messge here
xtw.Close();
}
Или вы даже можете использовать .NET 3.5 XElement и добавьте текст в StreamWriter
:
using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
XElement element = new XElement("Error");
// ... write error messge here
sw.WriteLine(element.ToString());
}
См. также статью Microsoft «Эффективные методы изменения больших файлов XML»
Во-первых, я бы дисквалифицировал System.Xml.XmlDocument, потому что это DOM , который требует синтаксического анализа и построения всего дерева в памяти, прежде чем его можно будет добавить. Это означает, что ваши 10 МБ текста будут более 10 МБ в памяти. Это означает, что он требует "большого объема памяти" и "времени".
Во-вторых, я бы дисквалифицировал System.Xml.XmlReader, потому что он требует сначала синтаксического анализа всего файла , прежде чем вы сможете понять, когда вы можете добавить к нему. Вам придется скопировать XmlReader в XmlWriter, поскольку вы не можете его изменить. Для этого необходимо продублировать ваш XML-код в памяти, прежде чем вы сможете его добавить.
Более быстрым решением для XmlDocument и XmlReader было бы манипулирование строкой (которое имеет свои собственные проблемы с памятью):
string xml = @"<Errors><error />...<error /></Errors>";
int idx = xml.LastIndexOf("</Errors>");
xml = xml.Substring(0, idx) + "<error>new error</error></Errors>";
Отрежьте конечный тег, добавьте новую ошибку и снова добавьте закрывающий тег.
Я полагаю, вы могли бы сходить с ума от этого и усечь свой файл на 9 символов и добавить к нему. Не нужно было бы читать файл и позволить ОС оптимизировать загрузку страницы (нужно было бы загружать только последний блок или что-то в этом роде).
System.IO.FileStream fs = System.IO.File.Open("log.xml", System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
fs.Seek(-("</Errors>".Length), System.IO.SeekOrigin.End);
fs.Write("<error>new error</error></Errors>");
fs.Close();
Это вызовет проблему, если ваш файл пуст или содержит только "<Ошибки > ", с которыми легко справиться, проверив длину.
Я бы использовал XmlDocument или XDocument для загрузки вашего файла, а затем обработал бы его соответствующим образом.
Затем я бы рассмотрел возможность кэширования этого XmlDocument в памяти, чтобы вы могли быстро получить доступ к файлу .
Зачем тебе скорость? У вас уже есть узкое место в производительности или вы ожидаете его?
Как ваш XML-файл представлен в коде? Вы пользуетесь System.XML-классами? В этом случае вы можете использовать XMLDocument.AppendChild.
Попробуйте это:
var doc = new XmlDocument();
doc.LoadXml("<Errors><error>This is my first error</error></Errors>");
XmlNode root = doc.DocumentElement;
//Create a new node.
XmlElement elem = doc.CreateElement("error");
elem.InnerText = "This is my error";
//Add the node to the document.
if (root != null) root.AppendChild(elem);
doc.Save(Console.Out);
Console.ReadLine();
Самым быстрым способом, вероятно, был бы прямой доступ к файлу.
using (StreamWriter file = File.AppendText("my.log"))
{
file.BaseStream.Seek(-"</Errors>".Length, SeekOrigin.End);
file.Write(" <Error>New error message.</Error></Errors>");
}
Но вы теряете все полезные функции XML и можете легко повредить файл.
Вот как это сделать в C, .NET должна быть похожей.
Игра заключается в простом переходе в конец файла, переходе назад по тегу, добавлении новой ошибки строку и напишите новый тег.
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char** argv) {
FILE *f;
// Open the file
f = fopen("log.xml", "r+");
// Small buffer to determine length of \n (1 on Unix, 2 on PC)
// You could always simply hard code this if you don't plan on
// porting to Unix.
char nlbuf[10];
sprintf(nlbuf, "\n");
// How long is our end tag?
long offset = strlen("</Errors>");
// Add in an \n char.
offset += strlen(nlbuf);
// Seek to the END OF FILE, and then GO BACK the end tag and newline
// so we use a NEGATIVE offset.
fseek(f, offset * -1, SEEK_END);
// Print out your new error line
fprintf(f, "<Error>New error line</Error>\n");
// Print out new ending tag.
fprintf(f, "</Errors>\n");
// Close and you're done
fclose(f);
}
The quickest method is likely to be reading in the file using an XmlReader
, and simply replicating each read node to a new stream using XmlWriter
When you get to the point at which you encounter the closing tag, then you just need to output your additional
element before coninuing the 'read and duplicate' cycle. This way is inevitably going to be harder than than reading the entire document into the DOM (XmlDocument
class), but for large XML files, much quicker. Admittedly, using StreamReader
/StreamWriter
would be somewhat faster still, but pretty horrible to work with in code.
Используя строковые методы (например, поиск до конца файла с последующим перемещением назад) длина закрывающего тега) уязвима для неожиданных, но вполне законных изменений в структуре документа.
В конце документа может быть любое количество пробелов, чтобы выбрать наиболее вероятную проблему, с которой вы столкнетесь. Он также может заканчиваться любым количеством комментариев или инструкций по обработке. А что произойдет, если элемент верхнего уровня не будет назван Ошибка
?
И вот ситуация, в которой использование строковых манипуляций полностью не обнаруживается:
<Error xmlns="not_your_namespace">
...
</Error>
Если вы используете XmlReader
для обработки XML, хотя это может быть не так быстро, как поиск EOF, он также будет позволяют обрабатывать все эти возможные исключения.