Пользовательский XML-маршал для массива со строкой между ними

#xml #go

#xml #Вперед

Вопрос:

У меня есть фрагмент XML, который мне нужно прочитать и записать. Это массив из, <condition> с <operator> между каждым, за исключением последнего объекта.

 <conditions>                                                                                                                                                                                                                                                                              
    <condition>                                                                                                                                                                                                                                                                           
      <label>a</label>                                                                                                                                                                                                                                                                    
    </condition>                                                                                                                                                                                                                                                                          
    <operator>AND</operator>                                                                                                                                                                                                                                                              
    <condition>                                                                                                                                                                                                                                                                           
      <label>b</label>                                                                                                                                                                                                                                                                    
    </condition>                                                                                                                                                                                                                                                                          
    <operator>AND</operator>                                                                                                                                                                                                                                                              
    <condition>                                                                                                                                                                                                                                                                           
      <label>c</label>                                                                                                                                                                                                                                                                    
    </condition>                                                                                                                                                                                                                                                                          
<conditions>
  

Моя модель Go выглядит следующим образом

 type Condition struct {                                                                                                                                                                                                                                                                   
    XMLName xml.Name `xml:"condition" json:"-"`                                                                                                                                                                                                                                           
    Label   string   `xml:"label"`                                                                                                                                                                                                                                                        
}                                                                                                                                                                                                                                                                                         

type Conditions struct {                                                                                                                                                                                                                                                                  
    ConditionList []Condition `xml:"condition,omitempty"`                                                                                                                                                                                                                                 
    Operator      string      `xml:"operator"`                                                                                                                                                                                                                                            
}   
  

Если я маршалирую структуру, оператор появляется только один раз внизу. как и ожидалось

 <Conditions>
  <condition>
    <label>a</label>
  </condition>
  <condition>
    <label>b</label>
  </condition>
  <condition>
    <label>c</label>
  </condition>
  <operator>AND</operator>
</Conditions>
  

Как мне заставить оператор появляться после каждого условия, кроме последнего?

Самое близкое, что я мог получить, это использовать оболочку

 func (c Conditions) MarshalXML(e *xml.Encoder, start xml.StartElement) error {                                                                                                                                                                                                            

    type tCondition struct {                                                                                                                                                                                                                                                              
        XMLName xml.Name `xml:"condition" json:"-"`                                                                                                                                                                                                                                       
        Label   string   `xml:"label"`                                                                                                                                                                                                                                                    
    }                                                                                                                                                                                                                                                                                     
    type tConditionWithOp struct {                                                                                                                                                                                                                                                        
        XMLName   xml.Name   `xml:"-" json:"-"`                                                                                                                                                                                                                                           
        Condition tCondition `xml: "conditions"`                                                                                                                                                                                                                                          
        Operator  string     `xml:",omitempty"`                                                                                                                                                                                                                                           
    }                                                                                                                                                                                                                                                                                     
    type tWrapper struct {                                                                                                                                                                                                                                                                
        OPS []tConditionWithOp                                                                                                                                                                                                                                                            
    }                                                                                                                                                                                                                                                                                     

    lst := make([]tConditionWithOp, 0, 10)                                                                                                                                                                                                                                                

    for idx, cond := range c.ConditionList {                                                                                                                                                                                                                                              
        tCond := tCondition{                                                                                                                                                                                                                                                              
            Label: cond.Label,                                                                                                                                                                                                                                                            
        }                                                                                                                                                                                                                                                                                 
        tCondOp := tConditionWithOp{                                                                                                                                                                                                                                                      
            Condition: tCond,                                                                                                                                                                                                                                                             
        }                                                                                                                                                                                                                                                                                 

        if idx < len(c.ConditionList)-1 {                                                                                                                                                                                                                                                 
            tCondOp.Operator = c.Operator                                                                                                                                                                                                                                                 
        }                                                                                                                                                                                                                                                                                 

        lst = append(lst, tCondOp)                                                                                                                                                                                                                                                        

    }                                                                                                                                                                                                                                                                                     
    wrapper := tWrapper{                                                                                                                                                                                                                                                                  
        OPS: lst,                                                                                                                                                                                                                                                                         
    }                                                                                                                                                                                                                                                                                     

    return e.EncodeElement(wrapper, start)                                                                                                                                                                                                                                                
}  
  

Но теперь у меня есть <OPS> тег

 <Conditions>
  <OPS>
    <condition>
      <label>a</label>
    </condition>
    <Operator>AND</Operator>
  </OPS>
  <OPS>
    <condition>
      <label>b</label>
    </condition>
    <Operator>AND</Operator>
  </OPS>
  <OPS>
    <condition>
      <label>c</label>
    </condition>
  </OPS>
</Conditions>
  

Я создал здесь игровую площадку

https://play.golang.org/p/gagQ3m3EMjY

Комментарии:

1. Ваша структура не представляет, как вы хотите, чтобы выглядел ваш вывод, и на самом деле это довольно сложно сделать таким образом. Вероятно, вам понадобится либо []interface{} с чередующимися Condition и Operator элементами, либо написать пользовательский MarshalXML метод для вашего типа.

Ответ №1:

Условия чередования и элементы оператора в массиве []interface{} сработали. Спасибо

 type Operator struct {                                                                                                                                       
    Name string                                                                                                                                              
}                                                                                                                                                            

func (op Operator) MarshalXML(e *xml.Encoder, start xml.StartElement) error {                                                                                
    start.Name.Local = "operator"                                                                                                                            
    return e.EncodeElement(op.Name, start)                                                                                                                   
}                                                                                                                                                            

func (c Conditions) MarshalXML(e *xml.Encoder, start xml.StartElement) error {                                                                               

    start.Name.Local = "conditions"                                                                                                                          
    var arr []interface{}                                                                                                                                    

    for idx, cond := range c.ConditionList {                                                                                                                 
        if idx > 0 {                                                                                                                                         
            arr = append(arr, Operator{Name: c.Operator})                                                                                                    
        }                                                                                                                                                    
        arr = append(arr, cond)                                                                                                                              
    }                                                                                                                                                        

    type root struct {                                                                                                                                       
        ARR []interface{}                                                                                                                                    
    }                                                                                                                                                        

    return e.EncodeElement(root{ARR: arr}, start)                                                                                                            
}