Search code examples
pythonpyyamljmespath

How can I get every URL from dictionary in Python?


I have a yaml string representing a menu. After I have a dictionary from it, I try to get URL simply said the key url of Parameter and every first element of list for other element that is not Parameter.

Here what I tried

import yaml
import jmespath
import pprint

setting = """
GeneralSetting:
  - Description: General Setting
MenuSetting:
  - Description: Menu Setting
  - Setting:
    - AutoMenu:
      - Description: Register menu
      - HelpText: This is for auto create menu
      - Value:
        - Sample:
          - Parameter:
            - icon: fa fa-birthday-cake
            - Active: Y
          - Sample: [Sample]
          - Sample Account: [SampleAccount]
        - Multi Journal:
          - Parameter:
            - icon: fas fa-book
            - url: MultiJournal
        - Foreign Exchange:
          - Parameter:
            - icon: fa fa-money-bill-alt
            - url: ForeignExchange
        - Loan Contract:
          - Parameter:
            - icon: fa fa-capsules
            - Active: Y
          - Loan Contract: [LoanContract,1]
          - Loan Report:
            - Loan Detail Listing: [LoanDetailListing,1]
            - Loan Application Detail Listing: [ReportR003,1]

"""

toDict = yaml.load(setting, yaml.SafeLoader)

pp = pprint.PrettyPrinter(indent=2)

# ALL
ALL       = jmespath.search('MenuSetting[].Setting[].AutoMenu[].Value[].*[]', toDict)
ParentURL       = jmespath.search('MenuSetting[].Setting[].AutoMenu[].Value[].*[0][].Parameter[].url', toDict)

NotParameter = {key:value for item in ALL for it in item for key,value in it.items() if key != "Parameter"}

# pp.pprint(NotParameter)

# print ('-----')
SubURL = jmespath.search('*[0]', NotParameter)

SubSubURL = jmespath.search('*[].*[][]', NotParameter)

pp.pprint(ParentURL)
print('---')
pp.pprint(SubURL)
print('---')
pp.pprint(SubSubURL)

From this, I could done well only for the Parent URL which is url under Parameter such as [MultiJournal,ForeignExchange] but not for child and sub-child.

I just want the final result of url as a list of this

[Sample,SampleAccount,MultiJournal,ForeignExchange,LoanContract,LoanDetailListing,Report/R003]

I tried several way but I still could not get the result of that?

Any way that I could get list of value as that? Thanks


Solution

  • Although I firmly believe that your YAML structure is not the one you should have (more on that lower), here would be a query matching your expected output:

    MenuSetting[].Setting[].AutoMenu[2].[Value[0].[Sample[].Sample, Sample[]."Sample Account"], Value[]."Multi Journal"[].Parameter[1].url, Value[]."Foreign Exchange"[].Parameter[1].url, Value[]."Loan Contract"[]."Loan Contract"[0], Value[]."Loan Contract"[]."Loan Report"[0]."Loan Detail Listing"[0], Value[]."Loan Contract"[]."Loan Report"[1]."Loan Application Detail Listing"[0]][][][][]
    

    Based on the JSON equivalent of your YAML:

    {
      "GeneralSetting": [
        {
          "Description": "General Setting"
        }
      ],
      "MenuSetting": [
        {
          "Description": "Menu Setting"
        },
        {
          "Setting": [
            {
              "AutoMenu": [
                {
                  "Description": "Register menu"
                },
                {
                  "HelpText": "This is for auto create menu"
                },
                {
                  "Value": [
                    {
                      "Sample": [
                        {
                          "Parameter": [
                            {
                              "icon": "fa fa-birthday-cake"
                            },
                            {
                              "Active": "Y"
                            }
                          ]
                        },
                        {
                          "Sample": [
                            "Sample"
                          ]
                        },
                        {
                          "Sample Account": [
                            "SampleAccount"
                          ]
                        }
                      ]
                    },
                    {
                      "Multi Journal": [
                        {
                          "Parameter": [
                            {
                              "icon": "fas fa-book"
                            },
                            {
                              "url": "MultiJournal"
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "Foreign Exchange": [
                        {
                          "Parameter": [
                            {
                              "icon": "fa fa-money-bill-alt"
                            },
                            {
                              "url": "ForeignExchange"
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "Loan Contract": [
                        {
                          "Parameter": [
                            {
                              "icon": "fa fa-capsules"
                            },
                            {
                              "Active": "Y"
                            }
                          ]
                        },
                        {
                          "Loan Contract": [
                            "LoanContract",
                            1
                          ]
                        },
                        {
                          "Loan Report": [
                            {
                              "Loan Detail Listing": [
                                "LoanDetailListing",
                                1
                              ]
                            },
                            {
                              "Loan Application Detail Listing": [
                                "ReportR003",
                                1
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
    

    This query gives:

    [
      "Sample",
      "SampleAccount",
      "MultiJournal",
      "ForeignExchange",
      "LoanContract",
      "LoanDetailListing",
      "ReportR003"
    ]
    

    Now I believe that your YAML has a lot of issue and that you are confusing lists and dictionaries in YAML.

    A list will start with a dash:

    - carrot
    - onions
    - potatoes
    

    A dictionary is a set of key/value pair all representing properties of the parent key:

    car:
      brand: ferrari
      model: 488
      engine: "3.9 l twin-turbocharged"
    

    You can, of course, have a list of dictionaries:

    - name: duck
      sound: quack
      legs: 2
    - name: cow
      sound: moo
      legs: 4
    

    So in your YAML, if I focus on the top of it I would believe it should rather be something along the line of:

    GeneralSetting:
      Description: General Setting
    MenuSetting:
      Description: Menu Setting
      Setting:
        AutoMenu:
          Description: Register menu
          HelpText: This is for auto create menu
          Value:
            Sample:
              Parameter:
                icon: fa fa-birthday-cake
                Active: Y
              Sample: Sample
              Sample Account: SampleAccount
            Multi Journal:
              Parameter:
                icon: fas fa-book
                url: MultiJournal
            Foreign Exchange:
              Parameter:
                icon: fa fa-money-bill-alt
                url: ForeignExchange 
    # ...
    

    Which, of course, would totally change and simplify the query, for example, based on this YAML, the resulting JSON would be:

    {
      "GeneralSetting": {
        "Description": "General Setting"
      },
      "MenuSetting": {
        "Description": "Menu Setting",
        "Setting": {
          "AutoMenu": {
            "Description": "Register menu",
            "HelpText": "This is for auto create menu",
            "Value": {
              "Sample": {
                "Parameter": {
                  "icon": "fa fa-birthday-cake",
                  "Active": "Y"
                },
                "Sample": "Sample",
                "Sample Account": "SampleAccount"
              },
              "Multi Journal": {
                "Parameter": {
                  "icon": "fas fa-book",
                  "url": "MultiJournal"
                }
              },
              "Foreign Exchange": {
                "Parameter": {
                  "icon": "fa fa-money-bill-alt",
                  "url": "ForeignExchange"
                }
              }
            }
          }
        }
      }
    }
    

    A query for the first elements would be:

    MenuSetting.Setting.AutoMenu.Value.[Sample.Sample, Sample."Sample Account", *.Parameter.url][]
    

    And this would give the expected:

    [
      "Sample",
      "SampleAccount",
      "MultiJournal",
      "ForeignExchange"
    ]