Преобразование XML: дублирование узла и строки объединения с существующими значениями тегов

Я новичок в xsltproc и хочу преобразовать этот XML:

<services>
    <event name = "Something.zip">
        <enabled>true</enabled>
        <bindings>
            <binding name = "Example">
                <machine>example-name</machine>
                <product>
                    <type>Shared</type>
                    <version>1.0</version>
                    <location>/path/to/something</location>
                </product>
            </binding>
        </bindings>
    </event>
</services>

На этот:

<services>
    <event name = "Something.zip">
        <enabled>true</enabled>
        <bindings>
            <binding name = "Example">
                <machine>example-name</machine>
                <product>
                    <type>Shared</type>
                    <version>1.0</version>
                    <location>/path/to/something</location>
                </product>
            </binding>
            <binding name = "Example-1">
                <machine>example-name-test</machine>
                <product>
                    <type>Shared</type>
                    <version>1.0</version>
                    <location>/path/to/something</location>
                </product>
            </binding>
        </bindings>
    </event>
</services>

Вот пункты, которым я должен следовать:

  1. Все исходное содержимое XML-файла должно быть сохранено.
  2. Внутри привязок мне нужно продублировать текущую привязку, взять ее имя и добавить к нему «-1». Кроме того, мне нужно добавить «-test» к значению внутри тега «machine».
  3. Имя каждой привязки может меняться, поэтому я не могу полагаться на строку «Пример» как на постоянный ввод. То же самое относится и к значению внутри тега «машина».
  4. Предположим, что в каждом XML-файле есть только один тег, и внутри него всегда будет 1 привязка.

Вставка.xsl, которую я написал:

<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" xmlns = "http://some/xml/namespace" xmlns:tc = "http://some/xml/namespace" exclude-result-prefixes = "tc">
    <xsl:output method = "xml" indent = "yes"/>
    <xsl:template match = "node()|@*">
        <xsl:copy>
            <xsl:apply-templates select = "node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match = "tc:binding">
        <xsl:copy-of select = "."/>
        <binding name = "{@name}-1">
            <xsl:copy-of select = "*"/>
        </binding>
    </xsl:template>
</xsl:stylesheet>

С помощью y.arazim я продублировал привязку внутри привязок и изменил атрибут имени, как было предложено. Тем не менее, не могу решить, как изменить новый блок привязки примера 1.

P.S. Если у меня есть значение тега с пробелами, удалит ли xsltproc эти пробелы и оставит вместо этого закрытый тег? Если да, есть ли возможность избежать такого поведения?

Рабочая таблица стилей:

<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" xmlns = "http://some/xml/namespace" xmlns:tc = "http://some/xml/namespace" exclude-result-prefixes = "tc">
    <xsl:output method = "xml" indent = "yes"/>
    <xsl:template match = "node()|@*">
        <xsl:copy>
            <xsl:apply-templates select = "node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match = "tc:binding">
        <xsl:copy-of select = "."/>
        <binding name = "{@name}-1">
            <machine>
                <xsl:value-of select = "concat(tc:machine, '-test')"/>
            </machine>
            <xsl:copy-of select = "*[not(self::tc:machine)]"/>
        </binding>
    </xsl:template>
</xsl:stylesheet>

После долгих поисков окончательным решением (на основе ответа y.arazim) было получение элементов xml из указанного пространства имен путем добавления префикса перед элементом.

Стоит ли изучать 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
0
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Почему-то ничего не происходит.

Это не правда. Он что-то делает: выдает ошибку:

Cannot add attributes to an element if children have been already added to the element.

Чтобы получить результат, который вы показываете, попробуйте что-то вроде:

<xsl:template match = "binding">
    <xsl:copy-of select = "."/>
    <binding name = "{@name}-1">
        <machine>
            <xsl:value-of select = "concat(machine, '-test')"/>
        </machine>
        <xsl:copy-of select = "product"/>
    </binding>
</xsl:template>

Обратите внимание, что ваша таблица стилей объявляет пространство имен по умолчанию xmlns = "http://some/xml/namespace". Я не знаю, действительно ли вы этого хотите или это просто попытка «программирования вуду», но это существенно изменит результат.


Ваш вопрос о пространствах см.: https://www.w3.org/TR/1999/REC-xslt-19991116/#strip


Добавлено: вы можете увидеть, как это работает здесь.

Я очень этого хочу, но маскирую это в целях безопасности. Что, если содержимое блока привязки может измениться? Есть ли какая-либо альтернатива строке <xsl:copy-of select = "product"/>, чтобы она копировала все содержимое блока привязки независимо от того, какой тег находится внутри нее?

Blurred_Vision 27.06.2024 10:00

Просто измените <xsl:copy-of select = "product"/> на <xsl:copy-of select = "*"/>

Michael Kay 27.06.2024 10:12

Вообще так и должно быть <xsl:copy-of select = "*[not(self::machine)]"/>. В противном случае вы получите еще одно появление элемента machine.

y.arazim 27.06.2024 10:38

Я попробовал ваше решение и сделал копию существующего в данный момент блока привязки с именем Пример-1 (что хорошо), затем вставил в него еще один <machine>-test</machine> (что нехорошо) и, наконец, вставил это " привязка» в существующий в данный момент «блок привязки», а не в родительский элемент. Я обновил шаблон.

Blurred_Vision 27.06.2024 11:48

Это не тот результат, который я получаю с предоставленными вами данными (см. ссылку в моем ответе). Возможно, разница вызвана тем, что ваш ввод находится в пространстве имен и вы не можете правильно его настроить.

y.arazim 27.06.2024 12:03

На самом деле, глядя на ваш отредактированный код, это совсем не то, что я предлагал.

y.arazim 27.06.2024 12:15

Вы правы. Я проверил еще раз, и это работает, но я получаю два тега с именем «machine»: <machine>-test</machine> и <machine>example-name</machine>.

Blurred_Vision 27.06.2024 12:24

Опять же, я не вижу, чтобы на выходе я получал данные, которые вы предоставили. Вы смотрели демо-версию, которую я предоставил по ссылке?

y.arazim 27.06.2024 12:31

Да, я видел скрипку. По какой-то причине рабочий пример работает отлично, но в моей ОС добавлен еще один тег <machine>-test</machine>. Это означает, что concat работает с пустым значением тега, а копия вообще не использует фильтр (хотя написано иначе).

Blurred_Vision 27.06.2024 12:59

Нет, это означает, что либо ваш ввод, либо ваш XSLT (или оба) различны. ИМХО, вы совершили серьезную ошибку, скрыв тот факт, что ваш входной XML находится в пространстве имен (в «целях безопасности» вы могли бы просто изменить URI пространства имен, как вы это сделали с XSLT), и теперь вы имеете дело с последствиями. К сожалению, я не знаю, как помочь вам с информацией, которую не вижу. И честно говоря, я уже потратил на это гораздо больше времени, чем планировал.

y.arazim 27.06.2024 13:35

@Blurred_Vision Наиболее вероятная причина, по которой вы получаете значение -test, заключается в том, что вы вызываете concat(machine, '-test'), но поскольку machine находится в пространстве имен, из XML не возвращается никакое значение. Узнайте, как правильно обрабатывать пространства имен во входном XML: stackoverflow.com/a/34762628/3016153.

michael.hor257k 27.06.2024 13:42

@michael.hor257k Великолепно. Большое спасибо, Михаил, упомянутая вами ссылка была для меня очень полезной и понятной.

Blurred_Vision 27.06.2024 14:42

@y.arazim Спасибо за ваш вклад и время, потраченное на эту проблему. Я отмечу ваш ответ как решение, потому что он был наиболее близким и внес наибольший вклад.

Blurred_Vision 27.06.2024 14:43

Я был бы склонен решить эту проблему, используя режимы:

<xsl:template match = "binding">
    <xsl:copy-of select = "."/>    
    <xsl:apply-templates select = "." mode = "dup"/>
</xsl:template>

<xsl:template match = "binding/@name" mode = "dup">
    <xsl:attribute name = "name">
      <xsl:value-of select = "concat(., '-1')"/>
    </xsl:attribute>
</xsl:template>

<xsl:template match = "binding/machine" mode = "dup">
    <xsl:copy>
      <xsl:value-of select = "concat(., '-test')"/>
    </xsl:copy>
</xsl:template>

и убедитесь, что шаблон удостоверения также применим к режиму dup.

Как «убедиться, что шаблон удостоверения также применим к режиму dup» в XSLT 1.0?

y.arazim 27.06.2024 10:44

Я не указал это подробно, потому что не использовал XSLT 1.0 более 20 лет, поэтому мне нужно поискать. Что вы могли бы сделать и сами. Похоже, вам нужно добавить еще одну копию правила шаблона удостоверения, которое определяет mode = "dup".

Michael Kay 28.06.2024 10:00

Я посмотрел это. Итак: 4 шаблона вместо одного? За что?

y.arazim 28.06.2024 22:39

Для разделения задач, модульности и возможности повторного использования.

Michael Kay 29.06.2024 18:40

Это благородные принципы. Но когда вы настаиваете на их реализации, невзирая ни на какие другие соображения, для этого есть уродливое слово.

y.arazim 29.06.2024 18:57

Ну, это оценочное суждение. Не зная предыстории проекта и его вероятных будущих направлений, невозможно предсказать, сколько усилий потребуется приложить для написания кода, который выдержит испытание временем.

Michael Kay 30.06.2024 21:01

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