XSLT копировать узел и изменять атрибуты - PullRequest
0 голосов
/ 28 ноября 2018

Я работаю с некоторыми очень большими XML-файлами, содержащими записи журналов.У меня есть несколько файлов XML с различными параметрами, хотя теги <record>, <date> и <message> присутствуют всегда.

Они выглядят примерно так (очень упрощенно):

data1.xml:

<record>
  <date>2018-10-01 00:00:00</date>
  <message>data1</message>
  <param key="Key1">Info</param>
  <param key="Key2">Info</param>
  <param key="Key3">Info</param>
</record>
<record>
  <date>2018-10-02 00:00:00</date>
  <message>data1</message>
  <param key="Key1">Info</param>
  <param key="Key2">Info</param>
  <param key="Key3">Info</param>
</record>

data2.xml:

<record>
  <date>2018-10-01 00:00:00</date>
  <message>data2</message>
  <param key="Key4">Info</param>
  <param key="Key5">Info</param>
</record>
<record>
  <date>2018-10-02 00:00:00</date>
  <message>data2</message>
  <param key="Key6">Info</param>
  <param key="Key7">Info</param>
</record>

data3.xml:

<record>
  <date>2018-10-01 00:00:00</date>
  <message>data3</message>
  <param key="Duration(h)">0:00:10</param>
  <attribute1>Info</attribute1>
</record>
<record>
  <date>2018-10-02 00:00:00</date>
  <message>data3</message>
  <param key="Duration(h)">0:01:30</param>
  <attribute1>Info</attribute1>
</record>

Я использую XSLT для фильтрации записей по ряду переменных, т. е. это может быть дата и сообщение или сообщение и ключ1 и т. д. и т. д.

Внутрииз XSLT все, что мне нужно сделать, это отфильтровать нужные записи и вызвать <xsl:apply-imports>, чтобы получить цепочку других файлов XSLT, которые управляют такими вещами, как сортировка вывода, форматирование и другие вещи.

I 'В настоящее время мы отфильтровываем нужные XML-узлы следующим образом:

Для этого примера давайте предположим, что я хочу, чтобы записи содержали <message>data1</message> и <message>data3</message>, и отредактировали их атрибуты, чтобы они отображались в виде таблицы.

filter1.xsl:

<!-- ignores records not matched by another template, so in this case 'data2' -->
<xsl:template match="record" /> 

<!-- applies imports to 'wanted' data -->
<xsl:template match="record[message='data1']"> 
  <xsl:apply-imports />
</xsl:template>

<!-- applies imports to 'wanted' data -->
<xsl:template match="record[message='data3']"> 
  <xsl:apply-imports />
</xsl:template>

<!-- rename 'param' to match the attribute from 'data3.xml' -->
<xsl:template match="param[@key='key1']">
  <xsl:copy>
    <xsl:attribute>attribute1</xsl:attribute>
    <xsl:value-of select="." />
  </xsl:copy>
</xsl:template>

Пока все хорошо, теперь мой вопрос.

Каждая запись в data3.xml отмечает конец операции, следовательно,параметр «длительность».Я хочу продублировать каждый узел, чтобы отметить начало этой операции.

Итак, для ввода:

<!-- marking end of operation -->
<record>
  <date>2018-10-01 00:00:00</date>
  <message>data3</message>
  <param key="Duration(h)">0:00:10</param>
  <attribute1>Info</attribute1>
</record>

Я хочу вывод:

<!-- marking start of operation -->
<record>
  <date>2018-09-30 23:59:50</date>
  <message>data3</message>
  <attribute1>Info</attribute1>
</record>
<!-- marking end of operation -->
<record>
  <date>2018-10-01 00:00:00</date>
  <message>data3</message>
  <param key="Duration(h)">0:00:10</param>
  <attribute1>Info</attribute1>
</record>

Но я не нашел, как дублировать весь узел и обработать их оба,Вот что я попробовал до сих пор:

Вызов именованного шаблона для создания нового узла на основе существующих атрибутов узлов. При этом не было вставлено ни одного узла вообще:

<xsl:template match="record[message='data3']">
  <xsl:call-template name="duplicateNode"></xsl:call-template>
  <xsl:apply-imports />
</xsl:template>

<xsl:template name="duplicatePrintedNode">
  <xsl:copy>
    <record>
      <date>2018-09-30 23:59:50</date>
      <message>data3</message>
      <attribute1>Info</attribute1>
    </record>
  </xsl:copy>
</xsl:template>

Копировать весь узелиспользуя <xsl:copy-of value"">.Казалось, это вставляет узел внутри атрибута существующего узла, который я хотел скопировать:

<xsl:template match="param[@key='Duration(h)']" mode="copy">
  <record>
    <xsl:copy>
      <xsl:copy-of select="@*"/>
    </xsl:copy>
  </record>
</xsl:template>

Так как я могу дублировать узел, изменить атрибуты, а затем применить шаблоны и импортироватьк обоим?

Я много раз искал в SO и Google, но ключевое слово copy, кажется, имеет несколько значений в контексте XSLT.Любая помощь будет оценена.

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Рассмотрим следующий (значительно) упрощенный пример:

XML

<input>
    <record>
        <date>2018-10-01 00:00:00</date>
        <message>data3</message>
        <param key="Duration(h)">0:00:10</param>
        <attribute1>Info</attribute1>
    </record>
</input>

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/input">
    <output>
        <xsl:apply-templates/>
    </output>
</xsl:template>

<xsl:template match="record[message='data3']">
    <xsl:copy>
        <date>new value</date>
        <xsl:copy-of select="node()[not(self::date or self::param)]"/>
    </xsl:copy>
    <xsl:copy>
        <xsl:copy-of select="node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Результат

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <record>
      <date>new value</date>
      <message>data3</message>
      <attribute1>Info</attribute1>
   </record>
   <record>
      <date>2018-10-01 00:00:00</date>
      <message>data3</message>
      <param key="Duration(h)">0:00:10</param>
      <attribute1>Info</attribute1>
   </record>
</output>

Примечание: Для целей этой демонстрации я использовал xsl:copy-of вместо xsl:apply-imports - поскольку мыне знаю, что это за импорт.

0 голосов
/ 28 ноября 2018

Я нашел способ сделать это, я понимаю, что образовательная ценность этого очень мала, потому что мой сценарий настолько специфичен, но я все равно опубликую его.Также спасибо @ michael.hor257k за попытку помочь.

Способ, которым я дублировал определенный узел и применил импорт к обоим, таков:

filter1.xsl

<!-- ignores records not matched by another template, so in this case 'data2' -->
<xsl:template match="record" /> 

<!-- applies imports to 'wanted' data -->
<xsl:template match="record[message='data1']"> 
  <xsl:apply-imports />
</xsl:template>

<!-- applies imports to 'wanted' data -->
<xsl:template match="record[message='data3']">
  <xsl:call-template name="duplicateNode"></xsl:call-template>
</xsl:template>

<!-- rename 'param' to match the attribute from 'data3.xml' -->
<xsl:template match="param[@key='key1']">
  <xsl:copy>
    <xsl:attribute>attribute1</xsl:attribute>
    <xsl:value-of select="." />
  </xsl:copy>
</xsl:template>

<!-- here I edit attributes to my liking, and then simply apply imports again -->
<xsl:template name="duplicateNode">
  <record>
    <date>
      <xsl:value-of select="./date" />
    </date>
    <message>data3 copy</message>
    <attribute1>Info</attribute1>
  </record>
  <xsl:apply-imports />
</xsl:template>
...