Модуль:XML
Материал из Викиэнциклопедия Московской областей
Пример
{{#invoke:XML|parseTest|1=<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"> <channel> <title>Yahoo! Weather - Klin, RS</title> <link>http://us.rd.yahoo.com/dailynews/rss/weather/Klin__RS/*http://weather.yahoo.com/forecast/RSXX1476_c.html</link> <description>Yahoo! Weather for Klin, RS</description> <language>en-us</language> <lastBuildDate>Mon, 03 Nov 2014 1:01 pm MSK</lastBuildDate> <ttl>60</ttl> <yweather:location city="Klin" region="" country="RS"/> <yweather:units temperature="C" distance="km" pressure="mb" speed="km/h"/> <yweather:wind chill="-3" direction="160" speed="6.44" /> <yweather:atmosphere humidity="91" visibility="9.99" pressure="1018" rising="0" /> <yweather:astronomy sunrise="8:45 am" sunset="5:47 pm"/> <image> <title>Yahoo! Weather</title> <width>142</width> <height>18</height> <link>http://weather.yahoo.com</link> <url>http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif</url> </image> <item> <title>Conditions for Klin, RS at 1:01 pm MSK</title> <geo:lat>56.35</geo:lat> <geo:long>36.75</geo:long> <link>http://us.rd.yahoo.com/dailynews/rss/weather/Klin__RS/*http://weather.yahoo.com/forecast/RSXX1476_c.html</link> <pubDate>Mon, 03 Nov 2014 1:01 pm MSK</pubDate> <yweather:condition text="Cloudy" code="26" temp="-1" date="Mon, 03 Nov 2014 1:01 pm MSK" /> <description><![CDATA[ <img src="http://l.yimg.com/a/i/us/we/52/26.gif"/><br /> <b>Current Conditions:</b><br /> Cloudy, -1 C<BR /> <BR /><b>Forecast:</b><BR /> Mon - Showers. High: 2 Low: -1<br /> Tue - Partly Cloudy. High: 6 Low: 1<br /> Wed - Sunny. High: 6 Low: 1<br /> Thu - Partly Cloudy. High: 6 Low: 2<br /> Fri - Rain. High: 7 Low: 4<br /> <br /> <a href="http://us.rd.yahoo.com/dailynews/rss/weather/Klin__RS/*http://weather.yahoo.com/forecast/RSXX1476_c.html">Full Forecast at Yahoo! Weather</a><BR/><BR/> (provided by <a href="http://www.weather.com" >The Weather Channel</a>)<br/> ]]></description> <yweather:forecast day="Mon" date="3 Nov 2014" low="-1" high="2" text="Showers" code="11" /> <yweather:forecast day="Tue" date="4 Nov 2014" low="1" high="6" text="Partly Cloudy" code="30" /> <yweather:forecast day="Wed" date="5 Nov 2014" low="1" high="6" text="Sunny" code="32" /> <yweather:forecast day="Thu" date="6 Nov 2014" low="2" high="6" text="Partly Cloudy" code="30" /> <yweather:forecast day="Fri" date="7 Nov 2014" low="4" high="7" text="Rain" code="12" /> <guid isPermaLink="false">RSXX1476_2014_11_07_7_00_MSK</guid> </item> </channel> </rss> <!-- api5.weather.bf1.yahoo.com Mon Nov 3 03:37:09 PST 2014 --> }}
table { 1 = <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> rss = table { geo = http://www.w3.org/2003/01/geo/wgs84_pos# yweather = http://xml.weather.yahoo.com/ns/rss/1.0 version = 2.0 channel = table { lastBuildDate = Mon, 03 Nov 2014 1:01 pm MSK description = Yahoo! Weather for Klin, RS link = http://us.rd.yahoo.com/dailynews/rss/weather/Klin__RS/*http://weather.yahoo.com/forecast/RSXX1476_c.html yweather:astronomy = table { sunrise = 8:45 am sunset = 5:47 pm } yweather:location = table { region = city = Klin country = RS } item = table { description = table { a = table { 1 = table { href = http://us.rd.yahoo.com/dailynews/rss/weather/Klin__RS/*http://weather.yahoo.com/forecast/RSXX1476_c.html value = Full Forecast at Yahoo! Weather } 2 = table { href = http://www.weather.com value = The Weather Channel } } img = table { src = http://l.yimg.com/a/i/us/we/52/26.gif } description = table { 1 = <![CDATA[ 2 = Cloudy, -1 C 3 = Mon - Showers. High: 2 Low: -1 Tue - Partly Cloudy. High: 6 Low: 1 Wed - Sunny. High: 6 Low: 1 Thu - Partly Cloudy. High: 6 Low: 2 Fri - Rain. High: 7 Low: 4 4 = (provided by 5 = ) ]]> } b = table { 1 = Current Conditions: 2 = Forecast: } } link = http://us.rd.yahoo.com/dailynews/rss/weather/Klin__RS/*http://weather.yahoo.com/forecast/RSXX1476_c.html pubDate = Mon, 03 Nov 2014 1:01 pm MSK yweather:forecast = table { 1 = table { low = -1 day = Mon code = 11 date = 3 Nov 2014 high = 2 text = Showers } 2 = table { low = 1 day = Tue code = 30 date = 4 Nov 2014 high = 6 text = Partly Cloudy } 3 = table { low = 1 day = Wed code = 32 date = 5 Nov 2014 high = 6 text = Sunny } 4 = table { low = 2 day = Thu code = 30 date = 6 Nov 2014 high = 6 text = Partly Cloudy } 5 = table { low = 4 day = Fri code = 12 date = 7 Nov 2014 high = 7 text = Rain } } title = Conditions for Klin, RS at 1:01 pm MSK yweather:condition = table { date = Mon, 03 Nov 2014 1:01 pm MSK text = Cloudy temp = -1 code = 26 } geo:lat = 56.35 geo:long = 36.75 guid = table { isPermaLink = false value = RSXX1476_2014_11_07_7_00_MSK } } image = table { title = Yahoo! Weather link = http://weather.yahoo.com height = 18 url = http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif width = 142 } title = Yahoo! Weather - Klin, RS yweather:atmosphere = table { humidity = 91 pressure = 1018 visibility = 9.99 rising = 0 } yweather:wind = table { speed = 6.44 direction = 160 chill = -3 } yweather:units = table { speed = km/h temperature = C distance = km pressure = mb } language = en-us ttl = 60 } } }
-- Роберту Иерусалимски
-- http://lua-users.org/wiki/LuaXml
local function parseargs(s)
local arg = {}
string.gsub(s, "([%-%w]+)=([\"'])(.-)%2", function (w, _, a)
arg[w] = a
end)
return arg
end
local function collect (s)
local stack = {}
local top = {}
table.insert(stack, top)
local ni,c,label,xarg, empty
local i, j = 1, 1
while true do
ni,j,c,label,xarg, empty = mw.ustring.find(s, "<(%/?)([%w:]+)(.-)(%/?)>", i)
if not ni then break end
local text = string.sub(s, i, ni-1)
if not mw.ustring.find(text, "^%s*$") then
table.insert(top, text)
end
if empty == "/" then -- empty element tag
table.insert(top, {label=label, xarg=parseargs(xarg), empty=1})
elseif c == "" then -- start tag
top = {label=label, xarg=parseargs(xarg)}
table.insert(stack, top) -- new level
else -- end tag
local toclose = table.remove(stack) -- remove top
top = stack[#stack]
if #stack < 1 then
error("nothing to close with "..label)
end
if toclose.label ~= label then
error("trying to close "..toclose.label.." with "..label)
end
table.insert(top, toclose)
end
i = j+1
end
local text = mw.ustring.sub(s, i)
if not mw.ustring.find(text, "^%s*$") then
table.insert(stack[#stack], text)
end
if #stack > 1 then
error("unclosed "..stack[#stack].label)
end
return stack[1]
end
-- Свёртывание таблицы в более читаемый формат:
local function compactify (tbl)
-- Завершение рекурсии:
if type (tbl) ~= 'table' then
return nil, tbl
end
-- В поле label имя тега:
local index = tbl.label or 1
tbl.label = nil
local ret = {}
-- Атрибуты тегов:
local attributes = false
if tbl.xarg then
for attr, val in pairs (tbl.xarg) do
attributes = true
ret [attr] = val
end
end
tbl.xarg = nil
-- Единственный элемент -- рекурсия скоро завершится:
local label, value
if #tbl == 1 then
label, value = compactify (tbl [1])
if label then
ret [label] = value
else
if type (value) == 'table' then
for k, v in pairs (value) do
ret [k] = v
end
else
if attributes then
ret.value = value
else
ret = value
end
end
end
else
-- Возможны и единичные и множественные теги:
local multiple = {}
for item, val in ipairs (tbl) do
label, value = compactify (val)
label = label or index
-- Этот тег оказался множественным:
if ret [label] and not multiple [label] then
ret [label] = {ret [label]}
multiple [label] = true
end
if multiple [label] then
ret [label] [#ret [label] + 1] = value
else
ret [label] = value
end
end
end
return index, ret
end
-- Удаление <br />
local function stripBR (str)
return mw.ustring.gsub (mw.ustring.gsub (str, '<br%s*/?>', ''), '<BR%s*/?>', '');
end
-- Интерфейс к {{#invoke:}}:
local p = {}
function p.parse (xml)
local _, ret = compactify (collect (stripBR (xml)))
return ret
end
function p.parseTest (frame)
local xml = frame.args [1]
return require ("Модуль:Test").serialise (p.parse (xml))
end
return p