Тип xml.EndElement

Тип xml.EndElement представляет закрывающий тег XML-элемента в пакете encoding/xml. Он используется совместно с xml.Decoder при пошаговом (token-based) разборе XML-документов. Структура содержит поле Name типа xml.Name, которое хранит локальное имя и пространство имен закрывающего тега. Этот тип возникает, когда декодер встречает закрывающий тег, например, </root>.

Структура

gotype EndElement struct {
  Name Name
}

Где поле Name содержит информацию о имени тега (локальное имя и пространство имен).

Синтаксис

Тип xml.EndElement не имеет собственных методов, он используется как маркер закрывающего тега при работе с токенами декодера. Обычно его получают через метод Decoder.Token или Decoder.DecodeElement, проверяя тип токена с помощью утверждения типа.

Пример использования с Decoder.Token

Следующий пример парсит XML-документ, извлекая названия элементов и показывая, когда встречается закрывающий тег:

gopackage main

import (
  "encoding/xml"
  "fmt"
  "strings"
)

func main() {
  data := `<book><title>Go Programming</title><author>John Doe</author></book>`
  decoder := xml.NewDecoder(strings.NewReader(data))

  for {
    token, err := decoder.Token()
    if err != nil {
      break
    }

    switch elem := token.(type) {
    case xml.StartElement:
      fmt.Printf("Start: %s\n", elem.Name.Local)
    case xml.EndElement:
      fmt.Printf("End: %s\n", elem.Name.Local)
    case xml.CharData:
      // Пропускаем текстовое содержимое
    }
  }
}

Результат выполнения кода:

go"Start: book"
"Start: title"
"End: title"
"Start: author"
"End: author"
"End: book"

В этом примере при встрече закрывающего тега срабатывает ветка xml.EndElement, и мы печатаем его локальное имя.

Пример проверки соответствия открывающему тегу

Можно использовать xml.EndElement для проверки правильности вложенности, сравнивая имена открывающего и закрывающего тегов:

gopackage main

import (
  "encoding/xml"
  "fmt"
  "strings"
)

func main() {
  data := `<root><item>one</item><item>two</item></root>`
  decoder := xml.NewDecoder(strings.NewReader(data))
  var lastStart xml.StartElement

  for {
    token, err := decoder.Token()
    if err != nil {
      break
    }

    switch elem := token.(type) {
    case xml.StartElement:
      lastStart = elem
    case xml.EndElement:
      if lastStart.Name.Local == elem.Name.Local {
        fmt.Printf("Matching pair: <%s>...</%s>\n", elem.Name.Local, elem.Name.Local)
      }
    }
  }
}

Результат выполнения кода:

go"Matching pair: <item>...</item>"
"Matching pair: <item>...</item>"
"Matching pair: <root>...</root>"

Здесь мы сохраняем последний открывающий тег и при встрече закрывающего сравниваем их имена.

Пример использования в структуре

Тип xml.EndElement также может использоваться как поле в структуре при декодировании XML с помощью тегов:

gopackage main

import (
  "encoding/xml"
  "fmt"
  "strings"
)

type CustomStruct struct {
  End xml.EndElement `xml:"end"`
}

func main() {
  data := `<root><end/></root>`
  var cs CustomStruct
  err := xml.Unmarshal([]byte(data), &cs)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Printf("End element name: %s\n", cs.End.Name.Local)
}

Результат выполнения кода:

go"End element name: end"

Обратите внимание, что для успешного разбора тег должен быть самозакрывающимся (<end/>), так как EndElement соответствует именно закрывающему тегу, а не открывающему.

Смотрите также

  • тип xml.StartElement,
    который представляет открывающий XML-тег
  • тип xml.Name,
    который хранит локальное имя и пространство имен
  • тип xml.Attr,
    который представляет атрибут XML-элемента
  • тип xml.CharData,
    который представляет текстовое содержимое