|
Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » CMD/BAT - [решено] парсинг xml :) |
|
CMD/BAT - [решено] парсинг xml :)
|
Пользователь Сообщения: 102 |
Суть:
Имеем xml файлы с содержимым вида: в данном случае представлены номер, координаты, погрешность. нас интересуют параметры Su_Nmb="хх" и Ord_Nmb="хх" параметр Ord_Nmb находится в той же строке что и все остальные значения и именно он является необходимым (а не Su_Nmb) обрабатывалось все кодом: For /F "Tokens=2-6 Delims= " %%a In ('C:\WINDOWS\system32\find.exe "Ordinate" ^<"%file_name%"') Do echo %%a %%b %%c %%e >> temp.txt но сейчас изменился формат xml файла и нужный номер точки записывается теперь в параметр Su_Nmb. вопрос: каким образом можно вытащить и связать в правильном соответствии номер точки и координаты, если они в разных строках (но строго друг за другом) ? второй вопрос: можно ли сразу вытаскивать лишь значения (вместо x="515401.19" сразу 515401.19) чтобы иметь возможность записывать в csv |
|
Отправлено: 09:46, 05-03-2014 |
Старожил Сообщения: 415
|
Профиль | Отправить PM | Цитировать Цитата firstarey:
2. Пишем её в Data (в кавычках - чтобы избежать неожиданных и неприятных ситуаций с необходимостью экранировать спецсимволы, из которых в XML в наличии как минимум, операторы перенаправления '>' и '<'). Чтобы было понятнее, наглядный пример: Set Test=ab>cd запишет в Test лишь "ab" и создаст пустой файл "cd", в то же время Set "Test=ab>cd" даст в качестве значения переменной именно то, что нужно. 3-7. Здесь всё идет немного не в том порядке, в котором оно исполняется. Опишу построчно, в порядке исполнения. Строка 29: Проверяем на соответствие первых восьми символов текущей строки началу логического блока, т.е. открывающего тэга "<Parcel ". Если есть совпадение, устанавливаем счетчик i в ноль и помечаем, что мы внутри блока: Set Block=true Там же читаем из открывающего тэга искомый номер CadastralNumber, вызывая одну из функций. Строка 37: Двойной IF, если это не открывающий тэг "<Parcel " И мы внутри блока (установлен флаг), инкрементируется значение i (счетчик строк) и соответствующая строка XML пишется в переменную BlockData_номер_строки. Строка 21: Если мы внутри блока и текущая строка = закрывающий тэг "</Parcel", сбрасываем пометку "внутри блока" и переходим к собственно, обработке данных (вызов функции Call :BlockData, которая работает с псевдомассивом из переменных BlockData_номер). Там же выводится пустая строка - просто визуальный разделитель, добавил для наглядности. Строка 26: После обработки данных удаляем значения всех переменных BlockData_номер. Для этого в цикле выводим все переменные (Set имя_переменной или часть имени выведет все переменные, с именем, подходящим под заданную строку в формате имя=значение), берем первую часть до = (имя) и удаляем их (назначаем пустое значение) Всё, с основной частью закончили, осталось разобрать функции. Цитата firstarey:
2. Инкрементируем n на единицу, так как изначально оно у нас было установлено в 0, а нумерация строк в блоке данных идет с единицы. Далее за каждый проход идёт такая же инкрементация на единицу. По сути, это "велосипедная" реализация бесконечного цикла (т.к. мы не знаем заранее, сколько у нас строк в блоке, а For /L %%? In (0,0,0) некорректно отрабатывает в данном случае). Можно бы было "подсмотреть" значение i, но на тот момент мне это не пришло в голову. 3. Если существует переменная BlockData_номер (она не пустая), то переходим к действиям с ней, иначе - выходим из функции. 4. Ищем строку с номером, так как она является отправной точкой, мы ищем именно её + следующую. Поиск осуществляется путём проверки (не)равенства "строка минус ключевое слово"=="строка". Ключевое слово у нас "Su_Nmb". Проверка равенства работает гораздо быстрее, чем вызов Find/FindStr 5. Когда строка найдена, допустим, она в переменной BlockData_3, нам надо определить и следующую, для этого используем заданный заранее сдвиг, в этом случае - одна строка. Если структура XML поменяется, не составит труда изменить нужный параметр. Т.е. к известному нам номеру строки прибавляем сдвиг и знаем, что координаты будут лежать в BlockData_4. Shift - назначенная в начале скрипта переменная, в конструкции Set /A она автоматически развернется в своё значение. 6. Дважды вызываем функцию для получения данных из обеих строк, в качестве параметра указываем само тело строки и ключевое слово для проверки. Оно служит для контроля - не изменилась ли структура? Если там будет что-то другое вместо ожидаемого, мы получим сообщение о ошибке парсинга XML. 7. Выводим полученные данные дважды - на экран, для визуального контроля, и дописываем в файл с результатом. "(!%KeyWord%! - и знак "!" и "%" ?)" - сначала мы через % разворачиваем KeyWord в Su_Nmb, а затем, через ! получаем значение Su_Nmb. Цитата firstarey:
2. Присваиваем Data переданный функции первый параметр, который мы строкой выше очистили от двойных кавычек и угловых скобок. 3. Опять тот же трюк с проверкой равенства. Если в строке не найдено ключевое слово, переданное функции вторым параметром, следовательно в строке не то, что мы ожидали, выводим ошибку парсинга. Для строки с номером точки это будет Su_Nmb, а для строки с координатами, соответственно, Ordinate 4. Если всё верно, проводим ряд манипуляций со строкой. а) Нам нужно убрать обрамляющие кавычки, в которые заключены значения координат b) Обрамляем переменную двойными кавычками по бокам и заменяем каждый пробел на кавычка+пробел+кавычка. В результате из Ordinate X="334527.77" Y="2175865.20" Ord_Nmb="1" Geopoint_Zacrep="626003000000" Delta_Geopoint="0.10" / "Ordinate" "X=334527.77" "Y=2175865.20" "Ord_Nmb=1" "Geopoint_Zacrep=626003000000" "Delta_Geopoint=0.10" "/" и далее, используя ещё один цикл, разбиваем на ещё более мелкие подстроки, используя в качестве разделителя "=", после чего присваиваем всё в форме ключ=значение, т.е. получаем переменную Delta_Geopoint со значением 0.10 и так далее. Для чего такая сложная система разбора подстрок? Чтобы не бежать переписывать скрипт, если вдруг во входных данных поменяются местами параметры, например X с Y, или ещё как изменится структура документа. Да, по сути это куча велосипедных реализаций и говнокода, но, к сожалению, cmd не имеет нативных инструментов для работы со структурированными данными вроде XML. Реализация на PowerShell, которую написал товарищ Iska, гораздо быстрее и проще, но и cmd пока рано списывать со счетов. |
|||
Последний раз редактировалось Anonymоus, 07-03-2014 в 14:03. Отправлено: 12:52, 07-03-2014 | #11 |
Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети. Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля. |
![]() |
Участник сейчас на форуме |
![]() |
Участник вне форума |
![]() |
Автор темы |
![]() |
Сообщение прикреплено |
| |||||
Название темы | Автор | Информация о форуме | Ответов | Последнее сообщение | |
CMD/BAT - Парсинг XML/TXT | mxm199 | Скриптовые языки администрирования Windows | 10 | 17-07-2012 12:34 | |
PowerShell - [решено] парсинг XML файла | dosperados | Скриптовые языки администрирования Windows | 2 | 02-07-2012 21:02 | |
7 / 2008 R2 - dot1x + xml profile + unattend.xml | HaeMHuK | Автоматическая установка Windows 11 / 10 / 8 / 7 / Vista | 0 | 20-10-2011 12:43 | |
CMD/BAT - Парсинг | Чин Хон | Скриптовые языки администрирования Windows | 1 | 04-02-2011 13:51 | |
[решено] проверка XML-файла на соответствие XML schema в IE 6 и Firefox 2 | dimait | Вебмастеру | 4 | 23-08-2007 02:02 |
|