Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » CMD/BAT - [решено] парсинг xml :)

Ответить
Настройки темы
CMD/BAT - [решено] парсинг xml :)

Пользователь


Сообщения: 102
Благодарности: 8

Профиль | Отправить PM | Цитировать


Суть:
Имеем xml файлы с содержимым вида:
читать дальше »
<Spelement_Unit Type_Unit="Точка" Su_Nmb="1">
<Ordinate X="515401.19" Y="2232958.98" Ord_Nmb="1" Num_Geopoint="182" Delta_Geopoint="0.10" />
</Spelement_Unit>
<Spelement_Unit Type_Unit="Точка" Su_Nmb="2">
<Ordinate X="515411.18" Y="2232958.64" Ord_Nmb="19" Num_Geopoint="183" Delta_Geopoint="0.10" />
</Spelement_Unit>
<Spelement_Unit Type_Unit="Точка" Su_Nmb="3">
<Ordinate X="515414.92" Y="2232958.50" Ord_Nmb="18" Num_Geopoint="184" Delta_Geopoint="0.10" />
</Spelement_Unit>
<Spelement_Unit Type_Unit="Точка" Su_Nmb="4">
<Ordinate X="515439.74" Y="2232960.55" Ord_Nmb="17" Num_Geopoint="185" Delta_Geopoint="0.10" />
</Spelement_Unit>
<Spelement_Unit Type_Unit="Точка" Su_Nmb="5">
<Ordinate X="515449.79" Y="2232961.65" Ord_Nmb="16" Num_Geopoint="239" Delta_Geopoint="0.30" />
</Spelement_Unit>
<Spelement_Unit Type_Unit="Точка" Su_Nmb="6">
<Ordinate X="515450.43" Y="2232970.92" Ord_Nmb="15" Num_Geopoint="240" Delta_Geopoint="0.30" />


в данном случае представлены номер, координаты, погрешность.
нас интересуют параметры
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
получаем результат вида:
читать дальше »
X="515401.19" Y="2232958.98" Ord_Nmb="1" Delta_Geopoint="0.10"


но сейчас изменился формат xml файла и нужный номер точки записывается теперь в параметр Su_Nmb.

вопрос:
каким образом можно вытащить и связать в правильном соответствии номер точки и координаты, если они в разных строках (но строго друг за другом) ?
второй вопрос:
можно ли сразу вытаскивать лишь значения (вместо x="515401.19" сразу 515401.19) чтобы иметь возможность записывать в csv

Отправлено: 09:46, 05-03-2014

 

Старожил


Сообщения: 415
Благодарности: 257

Профиль | Отправить PM | Цитировать


Цитата firstarey:
1. берем строку целиком
2. присваиваем в переменную data (почему в кавычках??)
3. если переменная block равна true если нашли строку начинающуюся на </Parcel (т.е. тут сначала выполняется второе if ? если выполнилось второе if, то переменной Block присвоить true?)
4. в переменную block записать значение false
5. вызываем blockData из цикла
6. пропускаем строку (так понимаю для наглядности отображения при выполнении, чтобы разбить блоки пустой строкой ?)
7. не понял эту строку.. в цикле берем первую подстроку после "=" из..(что делает ('Set BlockData_')??) и далее для меня тоже не понятно что выполняется в Do (Set %%B »
1. Берём строку целиком.
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:
1. как это работает и что нам дает? For %%A In (n d) Do Set %%A=0
2. добавить к переменной n единицу ?
3. если существует строка n (
4. если не существует строка n:Su_Nmb ... как это работает ?
5. в переменную d записать значение строки+(как cmd поймет Shift??)
6. вызываем GetData с параметром "номер строки" "Su_Nmb"
7. вызываем GetData с параметром "номер строки+shift" "Ordinate"
8. все еще внутри цикла выводим результат на экран (!%KeyWord%! - и знак "!" и "%" ?)
9. выводим найденное в файл результата
10. если не нашли нужную строку, то выход ?
11. повторили поиск нужной строки.. »
1. For %%A In (n d) Do Set %%A=0 - всего лишь вариант записи Set n=0 & Set d=0 Возможно, проще, правильнее и понятнее было бы записать именно так, но я по привычке засунул присвоение в цикл.
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:
1. берем из указанной параметром %~1 строки первую подстроку разделенную < и >. как работает %%?
2. присвоить переменной data.. а что ей присвоить ?
3. проверку тоже не понял. как сработает проверка значения ? переменная без первых двух значений проверяется на равенство самой себе
4. set data тоже не понял..
5. опять не понял.. »
1. Тут всё совсем просто. В первом параметре для функции содержится строка, которую надо обработать. Очищаем её от двойных кавычек (с помощью ~) и в цикле убираем угловые скобки, они же операторы перенаправления - они могут нам помешать. В цикле - потому что это проще, чем дважды вызывать Set. %%? - то же самое, что %%[A-aZ-z], просто вместо буквенного значения имени переменной используется вопросительный знак, это допустимо, хотя и не указано в справке к For /?
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" "/"
5. В следующем цикле разбираем строку на подстроки, т.е.
Код: Выделить весь код
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



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » CMD/BAT - [решено] парсинг xml :)

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
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




 
Переход