LINQ или XSLT для преобразования одного элемента в другой в Visual Basic 9

Укороченная версия:

Может ли кто-нибудь предложить или предоставить образец в LINQ to XML для VB или в XSLT того, как изменить один элемент XML на другой (без жесткого кодирования поэлементной копии всех неизмененных элементов)?

Фон:

У меня есть XML-файл, который, как мне кажется, сформирован правильно, который содержит корневую запись, которая называется <collection>, и несколько элементов <dvd>. На DVD есть жанры и теги, как показано ниже. (Я вырезал много других элементов для простоты).

Я хочу превратить любые элементы <Tag>, которые могут присутствовать, в дополнительный <Genre>. Например, в записи ниже мне нужно добавить <Genre> Kids</Genre>. (Я понимаю, что на самом деле это атрибут NAME элемента TAG, который я хочу превратить в элемент GENRE, но если бы я мог даже выяснить, как создать новый GENRE под названием «Tag», я бы намного продвинулся вперед и, вероятно, смог бы разгадать остальное.)

Я никогда особо ничего не делал с XML. Насколько я понимаю, я мог бы использовать файл преобразования XSLT и XSLCompiledTransform, или я мог бы использовать LINQ to XML (у меня Visual Basic 9, и я бы предпочел делать все это внутри VB). [Я уверен, что есть и другие подходы.]

Проблема в том, что я не могу найти никаких примеров синтаксиса XSLT или LINQ, которые говорят мне, как превратить один элемент в другой. Я мог бы написать достаточно LINQ, чтобы скопировать все элементы один за другим, но должен быть более простой способ, чем жесткое кодирование копии всех элементов, которые не меняются! (Должно быть!)

Итак, если кто-то, кто знает, может указать мне пример или помочь мне с небольшим начальным кодом в LINQ или XSLT, я был бы вечно благодарен (хорошо, может быть, не навсегда, но, по крайней мере, надолго!).

Спасибо.

Пример XML:

<Collection>
  <DVD>
    <ID>0000502461</ID>
    <Title>Cirque du Soleil: Alegría</Title>
    <Released>2002-05-31</Released>
    <RunningTime>90</RunningTime>
    <Genres>
      <Genre>Family</Genre>
      <Genre>Music</Genre>
    </Genres>
    <Overview>What if anything were possible? What if ...
    </Overview>
    <Notes/>
    <Tags>
      <Tag Name = "Kids" FullName = "Kids"/>
    </Tags>
  </DVD>
</Collection>
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
981
4

Ответы 4

Вы ищете что-то вроде этого:

 <xsl:template match = "Tag">
    <xsl:element name = "Genre">
      <xsl:value-of select = "@Name"/>           
    </xsl:element>    
  </xsl:template>

Вы можете сопоставить любой узел с node(), например:

<?xml version = "1.0" encoding = "utf-8"?>
<xsl:stylesheet version = "2.0"
    xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">

<!-- Uncomment to remove Tags elements -->
<!-- <xsl:template match = "Tags" /> -->

<xsl:template match = "Genres">
    <xsl:copy>
        <xsl:apply-templates select = "@*|node()" />
        <xsl:for-each select = "../Tags/Tag">
            <xsl:element name = "Genre">
                <xsl:value-of select = "@Name" />
            </xsl:element>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

<!-- Default rule: Copy node and descend -->
<xsl:template match = "@*|node()">
        <xsl:copy>
                <xsl:apply-templates select = "@*|node()"/>
        </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Используя один из самых фундаментальных и мощных шаблонов проектирования XSLT: переопределив шаблон удостоверения личности, можно написать это очень простое преобразование, чтобы заменить каждый элемент «Жанры» на элемент «Темы»:

<xsl:stylesheet version = "1.0"
 xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">

 <xsl:output omit-xml-declaration = "yes"/>

    <xsl:template match = "node()|@*">
      <xsl:copy>
         <xsl:apply-templates select = "node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match = "Genres">
      <Topics>
         <xsl:apply-templates select = "node()|@*"/>
      </Topics>
    </xsl:template>
</xsl:stylesheet>

При применении к предоставленному исходному XML-документу:

<Collection>
    <DVD>
        <ID>0000502461</ID>
        <Title>Cirque du Soleil: Alegría</Title>
        <Released>2002-05-31</Released>
        <RunningTime>90</RunningTime>
        <Genres>
            <Genre>Family</Genre>
            <Genre>Music</Genre>
        </Genres>
        <Overview>What if anything were possible? What if ...    </Overview>
        <Notes/>
        <Tags>
            <Tag Name = "Kids" FullName = "Kids"/>
        </Tags>
    </DVD>
</Collection>

Получен желаемый результат:

<Collection>
    <DVD>
        <ID>0000502461</ID>
        <Title>Cirque du Soleil: Alegría</Title>
        <Released>2002-05-31</Released>
        <RunningTime>90</RunningTime>
        <Topics>
            <Genre>Family</Genre>
            <Genre>Music</Genre>
        </Topics>
        <Overview>What if anything were possible? What if ...    </Overview>
        <Notes/>
        <Tags>
            <Tag Name = "Kids" FullName = "Kids"/>
        </Tags>
    </DVD>
</Collection>

Первый шаблон в таблице стилей - это правило идентификации. Он копирует любой согласованный узел без изменений и рекурсивно применяет шаблоны к его атрибутам или дочерним элементам. Если другого шаблона нет, этот шаблон создает идентичную копию исходного xml-документа, отсюда и его название.

Когда существует более конкретный шаблон (с указанием более конкретных деталей для согласованного узла, таких как имя и / или другие условия), говорят, что он «переопределяет» более общие шаблоны. Это означает, что для обработки узла выбран более конкретный шаблон.

Используя этот чрезвычайно мощный шаблон проектирования, легко реализовать в несколько строк такую ​​обработку, как:

  1. Удалите все узлы, удовлетворяющие некоторому условию.
  2. Переименуйте все узлы, удовлетворяющие некоторому условию.
  3. Измените содержимое всех узлов, удовлетворяющих некоторому условию

при копировании всех остальных узлов нетронутыми.

В нашем случае второй шаблон более конкретен и выбирается для обработки каждого элемента с именем «Жанры». Все, что он делает, - это создает элемент с именем «Темы» и внутри него применяет шаблоны ко всем текущим атрибутам и дочерним элементам узла.

Ну наконец то, следующее преобразование добавит новый элемент «Жанр» к дочерним элементам «Жанры» для каждого элемента «Тег».:

<xsl:stylesheet version = "1.0"
 xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">

 <xsl:output omit-xml-declaration = "yes"/>

    <xsl:template match = "node()|@*">
      <xsl:copy>
         <xsl:apply-templates select = "node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match = "Genres">
      <xsl:copy>
         <xsl:apply-templates select = "node()|@*"/>
         <xsl:apply-templates select = "../Tags/Tag" mode = "Gen"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match = "Tag" mode = "Gen">
      <Genre>
        <xsl:value-of select = "@Name"/>
      </Genre>
    </xsl:template>
</xsl:stylesheet>

Результат снова такой, как требуется:

<Collection>
    <DVD>
        <ID>0000502461</ID>
        <Title>Cirque du Soleil: Alegría</Title>
        <Released>2002-05-31</Released>
        <RunningTime>90</RunningTime>
        <Genres>
            <Genre>Family</Genre>
            <Genre>Music</Genre>
        <Genre>Kids</Genre>
        </Genres>
        <Overview>What if anything were possible? What if ...    </Overview>
        <Notes/>
        <Tags>
            <Tag Name = "Kids" FullName = "Kids"/>
        </Tags>
    </DVD>
</Collection>

Дополнительные фрагменты кода, использующие шаблон «правила идентификации», можно найти здесь.

Хорошее объяснение, но второе правило таблицы стилей и результат (без разницы для ввода ?!) кажутся неправильными.

phihag 27.11.2008 03:35

Пожалуйста, смотрите внимательно. Результат отличается от ввода. Элемента «Жанры» больше нет, он был заменен элементом «Темы». Это именно то, что нужно выполнить в этом вопросе: заменить определенный элемент другим элементом.

Dimitre Novatchev 27.11.2008 03:45

О, я видел, что OP также хотел, чтобы был добавлен новый «Жанр», соответствующий каждому «тегу» ... :( Готово!

Dimitre Novatchev 27.11.2008 03:57

У меня была такая же потребность в VB9, и я хотел использовать Linq вместо XSL. Я нашел это: http://msdn.microsoft.com/en-us/library/bb669154.aspx, и он работал очень хорошо.

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