XSLT - Как сохранить набор элементов, удаленных из исходного документа для повторного использования - PullRequest
0 голосов
/ 26 марта 2019

С учетом следующего XML:

<root>
  <group>
    <e1>001</e1>
    <e2>beep</e2>
    <e2>bop</e2>
    <e2>ork</e2>
    <e2>ah</e2>
    <e2>ah</e2>
  </group>
  <group>
    <e1>002</e1>
    <e2>beep</e2>
    <e2>bop</e2>
    <e2>ork</e2>
    <e2>ah</e2>
    <e2>ah</e2>
  </group>
  <group>
    <e1>003</e1>
    <e2>beep</e2>
    <e2>bop</e2>
    <e2>ork</e2>
    <e2>ah</e2>
    <e2>ah</e2>
  </group>
  <group>
    <e1>004</e1>
    <e2>beep</e2>
    <e2>bop</e2>
    <e2>ork</e2>
    <e2>ah</e2>
    <e2>ah</e2>
  </group>
</root>

Обратите внимание, что элементы 'e2' в каждом элементе 'group' одинаковы, и это гарантировано в исходном документе.

Я пытаюсь использовать XSLT для следующих шагов:

  1. сохранить копию набора элементов 'e2',
  2. стереть все элементы 'group',
  3. создать набор групповых элементов по умолчанию со вставленным в него набором e2s

Желаемый результат будет выглядеть так:

<root>
  <group>
    <e1>default1</e1>
    <e2>beep</e2>
    <e2>bop</e2>
    <e2>ork</e2>
    <e2>ah</e2>
    <e2>ah</e2>
  </group>
  <group>
    <e1>default2</e1>
    <e2>beep</e2>
    <e2>bop</e2>
    <e2>ork</e2>
    <e2>ah</e2>
    <e2>ah</e2>
  </group>
</root>

Значения 'e1' в исходном документе не имеют значения, а значения 'e2' в выходном документе известны заранее и являются статическими. Только значения 'e2' являются динамическими, и мне нужно убедиться, что они все есть.

Я использовал шаблон, подобный этому ранее, когда заменял все элементы с некоторыми жестко заданными значениями перед этим:

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

<!-- Empty Template eliminates all but first 'group' element. -->
<xsl:template match="//group[preceding::group]"></xsl:template>

<xsl:template match="//group">
  <xsl:element name="group">
    <e1>default1</e1>           
    <!-- e2 elements inserted here somehow? -->
  </xsl:element>
  <xsl:element name="group">
    <e1>default2</e1>           
    <!-- e2 elements inserted here somehow? -->
  </xsl:element>
</xsl:template>

Я пытался сохранить эти элементы в переменной, но ничего не было вставлено в выходной HTML:

<xsl:variable name="e2Elements" select="//group[1]/e2"></xsl:variable>
<xsl:template match="//group">
  <xsl:element name="group">
    <e1>default1</e1>           
    <xsl:copy-of select="$e2Elements" />
  </xsl:element>
</xsl:template>

Но я не уверен, как вставить элементы e2 в значения. Я использую SaxonHE9.8N и имею доступ к пространству имен exslt и xslt2.0

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

Ваше решение на самом деле делает ненужную копию элементов. Вы можете сделать это, не копируя их, например:

<xsl:variable name="e3Elements" select="//group[1]/e2" />

Другой неэффективностью является <xsl:template match="group[preceding::group]"/> Использование предыдущей оси всегда дорого, но особенно в шаблоне. Очевидное улучшение заключается в том, чтобы заменить его предшествующим родным братом (поиск по оси предшествующего родного брата выполняется намного быстрее, чем поиск по предыдущей оси). Но на самом деле вы можете сделать лучше, чем это: сделать это правило по умолчанию для групп (<xsl:template match="group"/>), а другое правило соответствовать только первой группе (<xsl:template match="group[1]">...).

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

С точки зрения стиля, <group> предпочтительнее, чем <xsl:element name="group">, просто потому, что он гораздо более читабелен.

Это будет мое решение XSLT 3.0:

<xsl:transform version="3.0" .... expand-text="yes">

  <xsl:template match="/">
    <xsl:variable name="e3Elements" select="//group[1]/e2"/>
    <xsl:for-each select="'default1', 'default2'">
      <group>
        <e1>{.}</e1>
        <xsl:copy-of select="$e3Elements"/>
      </group>
    </xsl:for-each>
  </xsl:template>

</xsl:transform>
1 голос
/ 26 марта 2019

Завелось, что мне нужно было сделать мою переменную копией элемента с помощью copy-of. Ниже мое решение:

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

<xsl:variable name="e3Elements">
    <xsl:copy-of select="//group[1]/e2" />
</xsl:variable>

<xsl:template match="group[preceding::group]"></xsl:template>

<xsl:template match="group">
    <xsl:element name="group">
        <xsl:element name="e1">default1</xsl:element>
        <xsl:copy-of select="$e3Elements"></xsl:copy-of>
    </xsl:element>
    <xsl:element name="group">
        <xsl:element name="e1">default2</xsl:element>
        <xsl:copy-of select="$e3Elements"></xsl:copy-of>
    </xsl:element>
</xsl:template>
...