Окончательный ответ следующий:
<!— Sample cut, relevant for this question —>
<config>
<disk dev="/dev/sda" label_type="msdos" unit_of_measurement="MiB">
<part num="1" size="500" p_type="primary" flags="boot" />
<part num="3" size="4096" p_type="primary" />
<part num="4" size="*" p_type="extended" />
<part num="7" size="4096" p_type="logical" />
<part num="5" size="*" p_type="logical" />
<part num="6" size="2048" p_type="logical" />
<part num="2" size="1024" p_type="primary" flags="swap" />
</disk>
</config>
Мы хотим следующий вывод, чтобы вывести раздел в таком порядке, чтобы мы могли создавать разделы в порядке внешнего вида на диске.Раздел размером * будет занимать все оставшееся пространство.Таким образом, он должен быть создан в конце.
Таким образом, нам нужно создать следующий раздел в последовательности.(начало и конец являются ссылочными указаниями, если нам нужно создать раздел, относящийся к началу доступного пространства или относительно конца доступного пространства)
/dev/sda;end;2;1024;MiB;primary;;;swap;;
/dev/sda;beginning;1;500;MiB;primary;;;boot;;
/dev/sda;beginning;3;4096;MiB;primary;;;;;
/dev/sda;beginning;4;*;MiB;extended;;;;;
/dev/sda;end;6;2048;MiB;logical;;;;;
/dev/sda;beginning;7;4096;MiB;logical;;;;;
/dev/sda;beginning;5;*;MiB;logical;;;;;
Получается путем запуска файла преобразования sxl с помощью:
xmlstarlet tr do_part.xsl ./disk-layout-complex.xml
А теперь код:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Call me with:
xmlstarlet tr do_part.xsl disk-layout.xml
Output: List of partitions to create in order.
Each line list the following values separated by semicolons:
- disk device
- creation reference
- partition number
- partition size
- partition size unit
- partition type
- partition id
- partition name
- partition flags
- lvm group it belongs to
- raid device it belongs to
Author: Olivier LAHAYE (c) 2019
Licence: GPLv2
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/config/disk"> <!-- We are loking for disk informations only -->
<!-- For each disk block -->
<xsl:call-template name="PrintPartition"> <!-- Compute primary or extended partitions to create -->
<xsl:with-param name="index"><xsl:value-of select="count(part)"/></xsl:with-param>
<xsl:with-param name="reference">end</xsl:with-param>
<xsl:with-param name="type">primary|extended</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="PrintPartition"> <!-- then, compute logical partitions to create -->
<xsl:with-param name="index"><xsl:value-of select="count(part)"/></xsl:with-param>
<xsl:with-param name="reference">end</xsl:with-param>
<xsl:with-param name="type">logical</xsl:with-param>
</xsl:call-template>
</xsl:template> <!-- We're done -->
<!-- Main recursive template that will dump partitions to create for the matched disk -->
<xsl:template name="PrintPartition">
<xsl:param name="index"/> <!-- partition node number within disk item-->
<xsl:param name="reference"/> <!-- beginning or end: should we create partition relative from beginning or from end of free space -->
<xsl:param name="type"/> <!-- type of partitions -->
<xsl:choose>
<xsl:when test="$index=1">
<xsl:if test="contains($type,part[position()=$index]/@p_type)">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
</xsl:when>
<xsl:when test="contains($type,part[position()=$index]/@p_type) and part[position()=$index]/@size!='*'">
<xsl:if test="$reference='end'">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference"><xsl:value-of select="$reference"/></xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
<xsl:if test="$reference='beginning'">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
</xsl:when>
<xsl:when test="contains($type,part[position()=$index]/@p_type) and part[position()=$index]/@size='*'">
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference">beginning</xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
<xsl:value-of select="concat(@dev,';','beginning;',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference"><xsl:value-of select="$reference"/></xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
И вуаля: он отлично работает.
Конечно, есть лучшие или более элегантные решения.(не стесняйтесь комментировать)
- вывод concat уродлив, но я не знаю, как придать ему более сексуальный вид
- содержит ($ type, part [position ()= $ index] / @ p_type) используется для проверки соответствия $ type (тип раздела) (test = "@ p_type = $ type" с $ type, содержащим «primary | extended» или «logic»)
- Я должен был использовать position () = $ index, когда я перемещаюсь в обратном порядке (от последнего элемента к 1-му элементу) (лучший способ, с помощью которого я выполняю сортировку foreach в обратном порядке)
- Мне нужно исправитьнесколько ошибок: (бесконечный цикл, если в разделе диска не объявлен раздел, создается уникальный раздел с переменным размером относительно конца диска. Хотя это работает, это не оптимально)
(коддоступно здесь (с небольшими изменениями): https://github.com/finley/SystemImager/blob/initrd-from-imageserver-and-dont-package-initrd/lib/dracut/modules.d/51systemimager/do_partitions.xsl)