I use Lua 5.1. I want to parse an XML file of the

2019-02-19 17:43发布

问题:

I tried using LuaXml library. But its functionality is limited as this returns only the first subtable of a particular attribute and does not go further than that. Then I tried string pattern matching which worked but I reached a dead end and it couldnt completely achieve the task. LuaExpat library is present in my lib folder of lua, and a file called lom.lua is also there. But often it doesnt work or gives me the error that "module not found"

My XML file looks like this :

<Service>
<NewInstance ref="5A">
<Std>DiscoveredElement</Std>
<Key>5A</Key>
<Attributes>
<Attribute name="TARGET_TYPE" value="weblogic_cluster" />
<Attribute name="DISCOVERED_NAME" value="/Farm_soa4_sys20_soa4_domain/soa4_domain/WSM4_Cluster" />
<Attribute name="BROKEN_REASON" value="0" />
<Attribute name="TARGET_NAME" value="/Farm_soa4_sys20_soa4_domain/soa4_domain/WSM4_Cluster" />
<Attribute name="EMD_URL" value="https://uxsys460.schneider.com:3872/emd/main/" />
</Attributes>
</NewInstance>

<NewInstance ref="6C">
<Std>DiscoveredElement</Std>
<Key>6C</Key>
<Attributes>
<Attribute name="TARGET_TYPE" value="oracle_weblogic_nodemanager" />
<Attribute name="SERVICE_TYPE" value=" " />
<Attribute name="ORG_ID" value="0" />
<Attribute name="TARGET_NAME" value="Oracle WebLogic NodeManager-uxlab090" />
</Attributes>
</NewInstance>

<NewInstance ref="98">
<Std>DiscoveredElement</Std>
<Key>98</Key>
<Attributes>
<Attribute name="TARGET_TYPE" value="composite" />
<Attribute name="SERVICE_TYPE" value=" " />
<Attribute name="TARGET_NAME" value="SYS-IMG-Grp" />
<Attribute name="EMD_URL" value="" />
</Attributes>
</NewInstance>

<NewRelationship>
<Parent>
<Instance ref="98" />
</Parent>
<GenericRelations>
<Relations type="contains">
<Instance ref="5A" />
</Relations>
</GenericRelations>
</NewRelationship>

<NewRelationship>
<Parent>
<Instance ref="5A" />
</Parent>
<GenericRelations>
<Relations type="contains">
<Instance ref="6C" />
</Relations>
</GenericRelations>
</NewRelationship>
<NewRelationship>
<Parent>
<Instance ref="5A" />
</Parent>
<GenericRelations>
<Relations type="contains">
<Instance ref="98" />
</Relations>
</GenericRelations>
</NewRelationship>
</Service>

My agenda is to display a NewInstance ID and its corresponding target type and target name and also its relation type with and the ID of instance ref its related to, along with its target type and target name for eg:

NewInstance ID - 5A
Target Type - weblogic_cluster 
Target Name - /Farm_soa4_sys20_soa4_domain/soa4_domain/WSM4_Cluster
Relation Type - contains
Instance ref - 6C
Target Type - oracle_weblogic_nodemanager
Target Name - Oracle WebLogic NodeManager-uxlab090
Instance ref - 98
Target Type - composite
Target Name - SYS-IMG-Grp

Now LuaXml cannot be used to achieve this. String pattern matching's code I'll list below and it helps me accomplish the task till relation type but not accurately

The code is :

a={}
b={}
c={}
d={}
p=0
i=0
q=0

local file = io.open("oem_topology_output.xml", "rb")   -- Open file   for    reading (binary data)
  for instance in file:read("*a"):gmatch("<NewInstance ref=\"(.-)\">") do
     a[i] = instance
     i = i+1
  end
file:close()
local files = io.open("oem_topology_output.xml", "rb")   -- Open file for  reading (binary data)
  for instances in files:read("*a"):gmatch("<NewInstance ref=\".-\">(.-)</NewInstance>") do
     TARGET_TYPE = instances:match('TARGET_TYPE.-value="(.-)"')
     TARGET_NAME = instances:match('TARGET_NAME.-value="(.-)"')
     b[p] = TARGET_TYPE
     c[p] = TARGET_NAME
     p =p+1
  end
local file = io.open("oem_topology_output.xml", "rb")   -- Open file   for   reading (binary data)
  for type in file:read("*a"):gmatch("<Relations type=\"(.-)\">") do
    d[q] = type
    q = q+1
  end
files:close()
for j=0,i-1 do
print("INSTANCE ID : ", a[j])
print("TARGET TYPE : ", b[j])
print("TARGET NAME : ", c[j])
print("RELATION TYPE : ",d[j])
end

Please suggest what approach I should follow to be able to parse the XMl file in the required way. Which in-built library will provide the apt functions. In case you suggest, LuaExpat let me know the possible reasons why it does not work for me.

回答1:

You don't need any special libraries to parse xml in lua, there is plenty of built in functionality to write your own parser.

For instance to retrieve the attributes of a node you can write something like this.

local file = "oem_topology_output.xml"
local node = "<(%a-)%s* "
local attributes = {
    "ref",
    "name",
    "value",
    "type"
}


for line in io.lines(file) do
    for a in line:gmatch(node) do
        for x = 1, #attributes do
            n = line:match(attributes[x]..'="(.-)"')
            if n then
                print(a, attributes[x], n)
            end
        end
    end
end

Which produces an output like

NewInstance ref 5A
Attribute   name    TARGET_TYPE
Attribute   value   weblogic_cluster
Attribute   name    DISCOVERED_NAME
Attribute   value   /Farm_soa4_sys20_soa4_domain/soa4_domain/WSM4_Cluster
Attribute   name    BROKEN_REASON
Attribute   value   0
Attribute   name    TARGET_NAME
Attribute   value   /Farm_soa4_sys20_soa4_domain/soa4_domain/WSM4_Cluster
Attribute   name    EMD_URL
Attribute   value   https://uxsys460.schneider.com:3872/emd/main/
NewInstance ref 6C
Attribute   name    TARGET_TYPE
Attribute   value   oracle_weblogic_nodemanager
Attribute   name    SERVICE_TYPE
Attribute   value    
Attribute   name    ORG_ID
Attribute   value   0
Attribute   name    TARGET_NAME
Attribute   value   Oracle WebLogic NodeManager-uxlab090
NewInstance ref 98
Attribute   name    TARGET_TYPE
Attribute   value   composite
Attribute   name    SERVICE_TYPE
Attribute   value    
Attribute   name    TARGET_NAME
Attribute   value   SYS-IMG-Grp
Attribute   name    EMD_URL
Attribute   value   
Instance    ref 98
Relations   type    contains
Instance    ref 5A
Instance    ref 5A
Relations   type    contains
Instance    ref 6C
Instance    ref 5A
Relations   type    contains
Instance    ref 98

No need to open or close a file, since there is no intent of writing to it.



回答2:

local a, b, c, d = {}, {}, {}, {}

local h = io.open("oem_topology_output.xml", "rb")   
if not h then return end
local txt = h:read("*a")
h:close()

for ref, instances in txt:gmatch('<NewInstance ref="(%w+)">(.-)</NewInstance>') do
    a[#a+1] = ref   
    TARGET_TYPE = instances:match('name="TARGET_TYPE"%s+value="(.-)"')
    if TARGET_TYPE then b[#b+1] = TARGET_TYPE end
    TARGET_NAME = instances:match('name="TARGET_NAME"%s+value="(.-)"')
    if TARGET_NAME then  c[#c+1] = TARGET_NAME end
end

for relationship in txt:gmatch('<NewRelationship>(.-)</NewRelationship>') do
    parent = relationship:match('<Parent>.-ref="(%w+)".-</Parent>')
    node = relationship:match('<Relations type="contains">.-ref="(%w+)".-</Relations>')
    if parent and node then    d[#d+1] = {  [parent] = node } end
end

for j=1,#a do
   local id = a[j]
    print("INSTANCE ID : ", id)
    print("TARGET TYPE : ", b[j])
    print("TARGET NAME : ", c[j])
    for k,v in  pairs(d) do
        if type(v)=='table' and v[id] then
            print("\tRELATION: ",v[id])
        end
    end
end

output:

INSTANCE ID :   5A
TARGET TYPE :   weblogic_cluster
TARGET NAME :   /Farm_soa4_sys20_soa4_domain/soa4_domain/WSM4_Cluster
    RELATION:   6C
    RELATION:   98
INSTANCE ID :   6C
TARGET TYPE :   oracle_weblogic_nodemanager
TARGET NAME :   Oracle WebLogic NodeManager-uxlab090
INSTANCE ID :   98
TARGET TYPE :   composite
TARGET NAME :   SYS-IMG-Grp
    RELATION:   5A