martinblech / xmltodict

Python module that makes working with XML feel like you are working with JSON
MIT License
5.52k stars 462 forks source link

Optional force separate dict for repetitive elements #350

Open gosplit opened 5 months ago

gosplit commented 5 months ago

I am using xmltodict to parse the config.xml of my Jenkins project settings.

The parameters section is with repetitive elements:

<parameterDefinitions>
        <ChoiceParameterDefinition>
          <name>ChoiceFirst</name>
          <choices>
              <string>Start</string>
              <string>Begin</string>
          </choices>
        </ChoiceParameterDefinition>
        <StringParameterDefinition>
          <name>Name</name>
          <defaultValue>foobar</defaultValue>
        </StringParameterDefinition>
        <StringParameterDefinition>
          <name>Address</name>
          <defaultValue>None</defaultValue>
        </StringParameterDefinition>
       <ChoiceParameterDefinition>
        <name>ChoiceFinal</name>
          <choices>
              <string>Final</string>
              <string>End</string>
          </choices>
       <ChoiceParameterDefinition>
      </parameterDefinitions>

The order of the elements is important for the Jenkins UI presentation. ChoiceFirst -> Name -> Address -> ChoiceEnd

However currently xmltodict would merge the same child elements in to a dict, and mess up the order: ChoiceFirst -> ChoiceEnd -> Name -> Address, even with force_list=('parameterDefinitions')

{ 
   parameterDefinitions: 
   [  
       {
          ChoiceParameterDefinition: [
            {  name: "ChoiceFirst",
                choices:  {  string: ["Start", "Begin"] }  },
            {  name: "ChoiceFinal",
                choices:  {  string: ["Final", "End"] }  },
         ]
       },{
         StringParameterDefinition: [
            {  name: "Name",
                defaultValue:  "foobar"  },
            {  name: "Address",
                defaultValue:  "None"  },
         ]
       },
   ]
}

So I am adding a parameter force_seperate_dict and will allow users to force the elements of "ChoiceParameterDefinition" to become individual dict by specifying force_seperate_dict=('ChoiceParameterDefinition') to keep the order.

{ 
   parameterDefinitions: 
   [  
       {  
           ChoiceParameterDefinition: 
            {  name: "ChoiceFirst",
                choices:  {  string: ["Start", "Begin"] }  },
        },  {
          StringParameterDefinition: 
            {  name: "Name",
                defaultValue:  "foobar"  },
       }, {
          StringParameterDefinition: 
            {  name: "Address",
                defaultValue:  "None"  },
       }, {  
           ChoiceParameterDefinition: 
           {  name: "ChoiceFinal",
                choices:  {  string: ["Final", "End"] }  },
        },
   ]
}

Two tests are added for this and also refactor the _should_force_list function to avoid duplication.