manoelcampos / xml2lua

XML Parser written entirely in Lua that works for Lua 5.1+. Convert XML to and from Lua Tables ๐ŸŒ–๐Ÿ’ฑ
MIT License
287 stars 73 forks source link

Duplicate tags sometimes not merge into array #55

Closed genmzy closed 3 years ago

genmzy commented 3 years ago
local xml2lua = require("xml2lua")
local handler = require("xmlhandler.tree")

local ivr_xml_str = [[
<?xml version="1.0" encoding="UTF-8" ?>
  <startMain>starMain</startMain>
  <errorKey>errorKey</errorKey>
  <noAnswerKey>noAnswerKey</noAnswerKey>
  <noAnswerTime>10</noAnswerTime>
  <menu>2</menu>
  <menus>
    <question>question2</question>
    <name>name1</name>
    <hasKeys>true</hasKeys>
    <isLast>false</isLast>
    <isMain>false</isMain>
    <keys>
      <key>*#</key>
      <content>**</content>
      <isEnd>true</isEnd>
      <isNextPoint>false</isNextPoint>
      <nextPoint/>
    </keys>
  </menus>
  <menus>
    <question>question2</question>
    <name>name2</name>
    <hasKeys>true</hasKeys>
    <isLast>false</isLast>
    <isMain>false</isMain>
    <keys>
      <key>*#</key>
      <content>##</content>
      <isEnd>true</isEnd>
      <isNextPoint>false</isNextPoint>
      <nextPoint/>
    </keys>
  </menus>
  <endMain>thanks you</endMain>
]]

local parser = xml2lua.parser(handler)
parser:parse(ivr_xml_str)

print(xml2lua.toString(handler.root))

The result:

{noAnswerKey=noAnswerKey,errorKey=errorKey,menus={question=question2,name=name2,isLast=false,keys={isNextPoint=false,content=##,nextPoint={},key=*#,isEnd=true},isMain=false,hasKeys=true},menu=2,noAnswerTime=10,endMain=thanks you,startMain=starMain}
genmzy commented 3 years ago

Latest version, by the way...

manoelcampos commented 3 years ago

Sorry for the late reply. Are you responsible for defining the XML structure? Despite that may be a valid XML, I don't think it's a good practice to place repeated tags outside an upper-level tag. A simplified version of your XML should be something like this:

<?xml version="1.0" encoding="UTF-8" ?>
  <menus>
        <menu>
            <question>question2</question>
            <name>name1</name>
            <keys>
              <key>*#</key>
              <content>**</content>
            </keys>
        </menu>
        <menu>
            <question>question2</question>
            <name>name2</name>
            <keys>
              <key>*#</key>
              <content>##</content>
            </keys>
        </menu>
  </menus>

Realise that if you have more than one <keys> tag for the same <menu>, the structure should follow the same approach.

manoelcampos commented 3 years ago

Please let me know your thoughts on that.

genmzy commented 3 years ago

Oh, I have no right to define the XML structure๐Ÿ˜‚ It seems the XML provider just convert JSON to XML(for some reason, JSON cannot be used) and throw it to me, the JSON structure like:

{
  "startMain": "starMain",
  "errorKey": "errorKey",
  "noAnswerKey": "noAnswerKey",
  "noAnswerTime": 7,
  "menu": 4,
  "menus": [
    {
      "question": "question1",
      "name": "menu1",
      "hasKeys": true,
      "isLast": true,
      "isMain": true,
      "keys": [
        {
          "key": 1,
          "content": "content1",
          "isEnd": false,
          "isNextPoint": true,
          "nextPoint": {
            "question": "question1",
            "name": "menu1-1",
            "hasKeys": true,
            "keys": [
              {
                "key": 1,
                "content": "question2",
                "isEnd": false,
                "isNextPoint": false,
                "nextPoint": null
              }
            ]
          }
        },
        {
          "key": 2,
          "content": "content2",
          "isEnd": false,
          "isNextPoint": false,
          "nextPoint": null
        }
      ]
    },
    {
      "question": "question2",
      "name": "stream",
      "hasKeys": true,
      "isLast": true,
      "isMain": true,
      "keys": [
        {
          "key": 3,
          "content": "content3",
          "isEnd": false,
          "isNextPoint": false,
          "nextPoint": null
        },
        {
          "key": 4,
          "content": "content4",
          "isEnd": false,
          "isNextPoint": false,
          "nextPoint": null
        }
      ]
    }
  ],
  "endMain": "End"
}

Now I have solved this by adding an additional tag to the outermost part of the XML structure. Thank you for your reply.๐Ÿ˜Š

manoelcampos commented 3 years ago

The issue here is that there isn't a native way to represent arrays in XML. Libs that convert any format to XML may suffer the same issue. A more natural resulting XML should be:

<?xml version="1.0" encoding="UTF-8"?>
<menus>
    <menu>
        <question>question1</question>
        <keys>
            <key>
                <key>1</key>
                <content>content1</content>
            </key>
            <key>
                <key>2</key>
                <content>content2</content>
            </key>
        </keys>
        <name>menu1</name>
    </menu>
    <menu>
        <question>question2</question>
        <keys>
            <key>
                <key>3</key>
                <content>content3</content>
            </key>
            <key>
                <key>4</key>
                <content>content4</content>
            </key>                
        </keys>
        <name>stream</name>
    </menu>
</menus>

The entries menus and keys are arrays. This way, the generated XML should have inner tags <menu> and <key>.

If you put the original XML with these upper-level <menus> and <keys> tags in some editor such as VS Code, it will show the XML is in fact invalid as I imagined.

<?xml version="1.0" encoding="UTF-8"?>
<menus>
    <question>question1</question>
    <keys>
        <key>1</key>
        <content>content1</content>
    </keys>
    <keys>
        <key>2</key>
        <content>content2</content>
    </keys>
    <name>menu1</name>
</menus>

<menus>
    <question>question2</question>
    <keys>
        <key>3</key>
        <content>content3</content>
    </keys>
    <keys>
        <key>4</key>
        <content>content4</content>
    </keys>
    <name>stream</name>
</menus>
Screen Shot 2021-03-31 at 09 15 24

I'll check if I can provide a workaround.

manoelcampos commented 3 years ago

Could you please try the version on the issue-55 branch for PR #57?

genmzy commented 3 years ago

Okay, I have tried, issue-55 branch works fine for me, thank you!๐Ÿ‘

manoelcampos commented 3 years ago

Hello @986299679 Thanks again for reporting. Check the new 1.5-0 version available on luarocks.