| 1 |
-------------------------------------------------------------------------------- |
|---|
| 2 |
-- Title: LUXMLInputStream.lua |
|---|
| 3 |
-- Description: Like a square peg in a round hole |
|---|
| 4 |
-- Author: Raphaël Szwarc http://alt.textdrive.com/lua/ |
|---|
| 5 |
-- Creation Date: February 1, 2005 |
|---|
| 6 |
-- Legal: Copyright (C) 2005 Raphaël Szwarc |
|---|
| 7 |
-------------------------------------------------------------------------------- |
|---|
| 8 |
|
|---|
| 9 |
-- import dependencies |
|---|
| 10 |
local LUInputStream = require( "LUInputStream" ) |
|---|
| 11 |
local LUBundle = require( "LUBundle" ) |
|---|
| 12 |
local LUMap = require( "LUMap" ) |
|---|
| 13 |
local LUString = require( "LUString" ) |
|---|
| 14 |
local string = require( "string" ) |
|---|
| 15 |
|
|---|
| 16 |
-- define the class |
|---|
| 17 |
local super = LUInputStream |
|---|
| 18 |
local self = super() |
|---|
| 19 |
|
|---|
| 20 |
-- class variable(s) |
|---|
| 21 |
local _entities = nil |
|---|
| 22 |
|
|---|
| 23 |
-- constant(s) |
|---|
| 24 |
self.Tag = 1 |
|---|
| 25 |
self.EndTag = 2 |
|---|
| 26 |
self.Text = 3 |
|---|
| 27 |
|
|---|
| 28 |
-- initialization method |
|---|
| 29 |
function self:init( aContent, anIndex, aLength ) |
|---|
| 30 |
self = super.init( self, aContent, anIndex, aLength ) |
|---|
| 31 |
|
|---|
| 32 |
self._type = self.Tag |
|---|
| 33 |
|
|---|
| 34 |
return self |
|---|
| 35 |
end |
|---|
| 36 |
|
|---|
| 37 |
-- method to read a tag |
|---|
| 38 |
function self:read() |
|---|
| 39 |
local aContent = self:content() |
|---|
| 40 |
local anIndex = self:index() |
|---|
| 41 |
|
|---|
| 42 |
if self._type ~= self.Text then |
|---|
| 43 |
local aStart = aContent:find( "%b<>", anIndex ) |
|---|
| 44 |
|
|---|
| 45 |
if aStart == nil then |
|---|
| 46 |
aStart = self:length() + 1 |
|---|
| 47 |
end |
|---|
| 48 |
|
|---|
| 49 |
if aStart ~= nil then |
|---|
| 50 |
local aText = aContent:sub( anIndex, aStart - 1 ) |
|---|
| 51 |
|
|---|
| 52 |
aText = LUString:trim( aText ) |
|---|
| 53 |
|
|---|
| 54 |
if aText:len() > 0 then |
|---|
| 55 |
aText = self:decode( aText ) |
|---|
| 56 |
|
|---|
| 57 |
self:setIndex( aStart - 1 ) |
|---|
| 58 |
|
|---|
| 59 |
self._type = self.Text |
|---|
| 60 |
|
|---|
| 61 |
return self.Text, aText |
|---|
| 62 |
end |
|---|
| 63 |
end |
|---|
| 64 |
end |
|---|
| 65 |
|
|---|
| 66 |
do |
|---|
| 67 |
local aStart, anEnd = aContent:find( "%b<>", anIndex ) |
|---|
| 68 |
|
|---|
| 69 |
if aStart ~= nil then |
|---|
| 70 |
local aTag = aContent:sub( aStart, anEnd ) |
|---|
| 71 |
local someAttributes = nil |
|---|
| 72 |
local aFunction = function ( aKey, _, aValue ) |
|---|
| 73 |
someAttributes = someAttributes or LUMap() |
|---|
| 74 |
someAttributes:put( aKey:lower(), self:decode( aValue ) ) |
|---|
| 75 |
end |
|---|
| 76 |
local aNameIndex = aTag:find( "[%c%s]+" ) or aTag:len() - 1 |
|---|
| 77 |
local aName = aTag:sub( 2, aNameIndex ):lower() |
|---|
| 78 |
|
|---|
| 79 |
aName = LUString:trim( aName ) |
|---|
| 80 |
aName = aName:gsub( "/+$", "" ) |
|---|
| 81 |
|
|---|
| 82 |
self:setIndex( anEnd + 1 ) |
|---|
| 83 |
|
|---|
| 84 |
-- as per http://lua-users.org/wiki/LuaXml |
|---|
| 85 |
aTag:gsub( "(%w+)=([\"'])(.-)%2", aFunction ) |
|---|
| 86 |
|
|---|
| 87 |
if aName:sub( 1, 1 ) == "/" then |
|---|
| 88 |
aName = aName:sub( 2, aName:len() ) |
|---|
| 89 |
|
|---|
| 90 |
self._type = self.EndTag |
|---|
| 91 |
|
|---|
| 92 |
return self.EndTag, aTag, aName, someAttributes |
|---|
| 93 |
else |
|---|
| 94 |
self._type = self.Tag |
|---|
| 95 |
|
|---|
| 96 |
return self.Tag, aTag, aName, someAttributes |
|---|
| 97 |
end |
|---|
| 98 |
end |
|---|
| 99 |
end |
|---|
| 100 |
|
|---|
| 101 |
return nil |
|---|
| 102 |
end |
|---|
| 103 |
|
|---|
| 104 |
-- method to read a text |
|---|
| 105 |
function self:readChar() |
|---|
| 106 |
while true do |
|---|
| 107 |
local aType, aContent, aName, someAttributes = self:read() |
|---|
| 108 |
|
|---|
| 109 |
if aType == self.Text then |
|---|
| 110 |
return aContent |
|---|
| 111 |
elseif aType == nil then |
|---|
| 112 |
break |
|---|
| 113 |
end |
|---|
| 114 |
end |
|---|
| 115 |
|
|---|
| 116 |
return nil |
|---|
| 117 |
end |
|---|
| 118 |
|
|---|
| 119 |
-- private method to decode a given entity |
|---|
| 120 |
local function CharWithEntity( aSymbol, anEntity ) |
|---|
| 121 |
if aSymbol == "#" then |
|---|
| 122 |
local aCode = tonumber( ( anEntity:gsub( "^x", "0x" ) ) ) |
|---|
| 123 |
|
|---|
| 124 |
if aCode ~= nil and aCode < 256 then |
|---|
| 125 |
return string.char( aCode ) |
|---|
| 126 |
end |
|---|
| 127 |
else |
|---|
| 128 |
local aValue = self:entities():get( anEntity ) |
|---|
| 129 |
|
|---|
| 130 |
if aValue ~= nil then |
|---|
| 131 |
return aValue |
|---|
| 132 |
end |
|---|
| 133 |
end |
|---|
| 134 |
|
|---|
| 135 |
return ( "&%s%s;" ):format( aSymbol, anEntity ) |
|---|
| 136 |
end |
|---|
| 137 |
|
|---|
| 138 |
-- method to decode a given string |
|---|
| 139 |
function self:decode( aString ) |
|---|
| 140 |
if aString ~= nil then |
|---|
| 141 |
aString = aString:gsub( "&(#?)(%w+);", CharWithEntity ) |
|---|
| 142 |
end |
|---|
| 143 |
|
|---|
| 144 |
return aString |
|---|
| 145 |
end |
|---|
| 146 |
|
|---|
| 147 |
-- method to access the entities |
|---|
| 148 |
function self:entities() |
|---|
| 149 |
if _entities == nil then |
|---|
| 150 |
local aBundle = LUBundle:bundleWithName( "LUXMLInputStream" ) |
|---|
| 151 |
local aFile = aBundle:fileWithName( "LUXMLInputStream", "txt" ) |
|---|
| 152 |
|
|---|
| 153 |
_entities = LUMap():load( aFile ) |
|---|
| 154 |
end |
|---|
| 155 |
|
|---|
| 156 |
return _entities |
|---|
| 157 |
end |
|---|
| 158 |
|
|---|
| 159 |
return self |
|---|