Я уже немного ломаю голову над этим и не могу понять, как это сделать.
У меня есть следующий XML-подобный блок:
<xml>
<node id = "1">
<item>2</item>
</node>
<node id = "3">
<item>4</item>
</node>
<special id = "5">
<item>6</item>
</special>
<node id = "7">
<item>8</item>
</node>
<node id = "9">
<item>10</item>
</node>
<node id = "11">
<item>12</item>
</node>
</xml>
Что мне нужно сделать, так это найти значение атрибута «id» для «специального» узла. Затем мне нужно уменьшить любые атрибуты «id», которые больше, чем «специальный», на разницу между специальным «id» и более высоким значением, а затем удалить «специальный» узел. Таким образом, пример вывода будет таким:
<xml>
<node id = "1">
<item>2</item>
</node>
<node id = "3">
<item>4</item>
</node>
<node id = "5">
<item>8</item>
</node>
<node id = "7">
<item>10</item>
</node>
<node id = "9">
<item>12</item>
</node>
</xml>
Я знаю, как удалить «особый» узел, я думал, что понял, как получить переменную, но я не смог заставить это работать.
Я использую XSLT 1.0, вот что у меня есть:
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration = "yes"/>
<xsl:variable name = "myvar" select = "//special/@id"/>
<xsl:template match = "@*|node()">
<xsl:copy>
<xsl:apply-templates select = "@*|node()"/>
</xsl:copy>
</xsl:template>
<!--drop special-->
<xsl:template match = "//special">
</xsl:template>
<!-- this is totally not working, what am I doing wrong? -->
<xsl:template match = "//node/@id">
<xsl:choose>
<xsl:when test = "current() > myvar">
<xsl:attribute name = "id">
<xsl:value-of select = "'-1'"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Изменить. Уточнение комментария по уменьшению: Извините, было поздно, и, видимо, я не разобрался с обновлением других идентификаторов, и я попытался слишком упростить свой случай, чтобы привести как можно более простой пример. Видимо, я пошел слишком просто и развернулся. Мне нужна разница между первым большим идентификатором и идентификатором, который я удаляю, а затем мне нужно вычесть эту разницу из всех идентификаторов, превышающих «специальный». Таким образом, первый обновленный идентификатор изменится на 5, второй обновленный идентификатор изменится на 7, затем на 9 и т. д. Я обновил входной XML-код примера и желаемый результат.
Правильно ли я понимаю, что «уменьшить любые атрибуты «id», которые больше, чем «специальный», на разницу между специальным «id» и более высоким значением»? Это просто сложный способ сказать «замените значение атрибута 'id' значением специального 'id'»?
Я обновил сообщение, чтобы уточнить комментарий по уменьшению, надеюсь.
Боюсь, вы не добавили ясности к тому, что сказали ранее. b - (b - a) = a
. Таким образом, любой идентификатор, который больше, чем переменная $myvar, в конечном итоге будет равен $myvar. Если их несколько, вы получите дубликаты идентификаторов.
Вы абсолютно правы. Я обновил обновление >_<
Можно ли предположить, что существует только один элемент special
и что первый элемент node
с большим id
является его ближайшим братом?
@ michael.hor257k да, есть только 1 специальное значение узла, и все последующие идентификаторы будут больше, и их идентификаторы должны быть уменьшены на разницу между первым большим идентификатором и специальным идентификатором ... если это имеет смысл .. ..надеюсь, пример, который я обновил выше, более понятен.
Хорошо, поэтому я считаю, что мой ответ, приведенный ниже, должен сработать для вас.
В XSLT 2.0+ я бы использовал правило
<xsl:template match = "node/@id[number(.) > $myvar]">
<xsl:attribute name = "id" select = "$myvar"/>
</xsl:template>
Примечание: «//» в начале шаблона соответствия почти всегда является пустой тратой места.
Примечание. Помещение условия в шаблон соответствия всегда кажется лучшим стилем кодирования, чем правило шаблона, непосредственным содержимым которого является xsl:choose.
В версии 1.0, как всегда, это немного более многословно, потому что вы не можете ссылаться на глобальные переменные в шаблонах соответствия. Поэтому я бы написал вместо этого:
<xsl:template match = "node/@id[number(.) > number(//special/@id)]">
<xsl:attribute name = "id">
<xsl:value-of select = "$myvar"/>
</xsl:attribute>
</xsl:template>
(за исключением того, что вы не найдете меня на самом деле пишущим XSLT 1.0, если я не в отчаянии...)
Я читаю decrment любые атрибуты «id», которые больше, чем «специальный», по разнице между специальным «id», как довольно неясный способ сказать, если значение id больше, чем специальное, а затем заменить его на особенный.
Я очень сомневаюсь, что им понадобится более одного узла с одним и тем же идентификатором.
Можно только догадываться.
Можно подождать разъяснений ОП.
Большое спасибо. Извините, что было поздно, и, видимо, я не разобрался с обновлением других идентификаторов... Итак, любые идентификаторы, которые больше, чем переменная, которую мне нужно установить в current_id - (current_id - myvar). Итак, если текущий ID равен 7, а myvar равен 5, новый ID будет 7 - (7 - 5) = 5.
Формула x - (x - y)
упрощается до y
.
Вы абсолютно правы. Я обновил обновление, чтобы улучшить пример и то, что мне нужно. Надеюсь, результат объясняет лучше, чем я могу словами.
Я предполагаю, что за это проголосовали, потому что я ответил на вопрос, как написано, а не на вопрос, как предполагалось. Что ж, у меня толстая кожа и куча репутации на такие вещи.
Если можно предположить, что все значения id
в исходном XML находятся в порядке возрастания (и что будет ровно один элемент special
), вы можете сделать просто:
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 = "/xml">
<xsl:copy>
<!-- nodes preceding special -->
<xsl:copy-of select = "special/preceding-sibling::node"/>
<!-- nodes following special -->
<xsl:variable name = "tail" select = "special/following-sibling::node" />
<xsl:variable name = "diff" select = "$tail[1]/@id - special/@id" />
<xsl:for-each select = "$tail">
<node id = "{@id - $diff}">
<xsl:copy-of select = "*"/>
</node>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Пожалуйста, уточните это: «Затем мне нужно уменьшить любые атрибуты «id», которые больше, чем «специальный», на разницу между специальным «id» и более высоким значением». В моей арифметике результат всегда будет равен значению специального идентификатора.