Как получить доступ к родственному элементу с помощью Go с XML-пакетом etree?

Учитывая XML-документ, такой как этот:

<MasterXML>
    <Processes>
        <Params>
            <ParamName>today</ParamName>
            <ParamType>1</ParamType>
            <ParamValue/>
        </Params>
       <Params>
            <ParamName>today</ParamName>
            <ParamType>2</ParamType>
            <ParamValue/>
        </Params>
       <Params>
            <ParamName>today</ParamName>
            <ParamType>3</ParamType>
            <ParamValue/>
        </Params>
    </Processes>
</MasterXML>

Используя пакет beevik/etree для Go, как я могу получить доступ к <ParamValue/> для каждого экземпляра <Params> в документе, чтобы заполнить его значением, когда <ParamName> имеет определенное, конкретное значение.

В данном примере я бы хотел заполнить все узлы <ParamValue/> во всех узлах <Params> датой 02.05.2024, когда <ParamName> имеет значение сегодня.

Этот код работает только с первым экземпляром узла <Params> в документе, содержащем множество экземпляров, где <ParamName>== Today , хотя цикл, по-видимому, должен обращаться к каждому экземпляру <Params>:

    for _, elem1 := range doc.FindElements(".//Processes//Params//ParamName") {
    
            if elem1 == nil {
                log.Fatal("Check XPath)
            }
    
            s := elem1.Text()
    
            if s == "today" {
                elem2 := elem1.FindElement("//ParamValue")
                elem2.SetText("05/02/2024")
            }
    }

Как я могу это сделать? Почему range doc.FindElements(".//Processes//Params//ParamName") не находит все экземпляры <Params>? Должен ли я использовать другой подход?

Ваш XML недействителен. Processes не имеет закрывающего тега.

frankenapps 03.05.2024 20:07

@frankenapps — исправлено, спасибо. (Не имеет отношения к вопросу — это всего лишь пример кода.)

Vector 03.05.2024 20:12

В вашем примере кода также есть проблема: условие if неверно, поскольку в XML строка «сегодня» заключена в пробелы (например, «сегодня»), поэтому условие никогда не совпадает.

frankenapps 03.05.2024 20:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш текущий код ведет себя так, как вы описали, потому что, используя двойную косую черту в XPath, вы всегда выполняете поиск по дереву XML рекурсивно, то есть всегда находите первое вхождение сверху.

Это также означает, что FindElements всегда работал так, как вы думали (что можно легко проверить, раскомментировав оператор println ниже или запустив код через отладчик).

Чтобы действительно добиться желаемого поведения, ваш оператор XPath должен быть скорректирован:

  • .. перемещается на один уровень вверх в иерархии (помните, что elem1 уже находится на уровне ParamName, поэтому, поднявшись на один уровень вверх, вы теперь находитесь на уровне Params
  • одинарная косая черта (/) находит следующий элемент на текущем уровне
  • в нашем случае так и должно быть ParamValue

поэтому правильный XPath будет ../ParamValue".

Вот фиксированный образец:

package main

import (
    "log"
    "os"
    "strings"

    "github.com/beevik/etree"
)

func main() {
    doc := etree.NewDocument()
    if err := doc.ReadFromFile("master.xml"); err != nil {
        panic(err)
    }

    for _, elem1 := range doc.FindElements(".//Processes//Params//ParamName") {

        if elem1 == nil {
            log.Fatal("Check XPath")
        }

        s := elem1.Text()
        //println(s)

        if strings.TrimSpace(s) == "today" {
            elem2 := elem1.FindElement("../ParamValue")
            elem2.SetText("05/02/2024")
        }
    }

    doc.WriteTo(os.Stdout)
}

Для этого потребуется master.xml в том же каталоге, что и ваш .go файл.

Я пошел с этим:

<MasterXML>
    <Processes>
        <Params>
            <ParamName> today </ParamName>
            <ParamType>1</ParamType>
            <ParamValue/>
        </Params>
       <Params>
            <ParamName> tomorrow </ParamName>
            <ParamType>2</ParamType>
            <ParamValue/>
        </Params>
       <Params>
            <ParamName> today </ParamName>
            <ParamType>3</ParamType>
            <ParamValue/>
        </Params>
    </Processes>
</MasterXML>

который дает желаемый результат:

<MasterXML>
    <Processes>
        <Params>
            <ParamName> today </ParamName>
            <ParamType>1</ParamType>
            <ParamValue>05/02/2024</ParamValue>
        </Params>
       <Params>
            <ParamName> tomorrow </ParamName>
            <ParamType>2</ParamType>
            <ParamValue/>
        </Params>
       <Params>
            <ParamName> today </ParamName>
            <ParamType>3</ParamType>
            <ParamValue>05/02/2024</ParamValue>
        </Params>
    </Processes>
</MasterXML>

Другие вопросы по теме