Как выбрать прародителя узла с помощью xslt

Я нахожусь в ситуации, когда я могу тестировать только дочерний узел, но я должен применить теги к прародителю этого дочернего узла.

Я пытался использовать:

<xsl:call-template name="grandparent" select="parent::parent::node()"/>

а также:

<xsl:call-template name="grandparent" select="ancestor::node [@nameofgrandparentnode]"/>

Но ни один не работает.

Уровень родительского узла не является фиксированным, поэтому я полагаю, что я не могу использовать [@level=#]. Любые идеи о том, как выбрать его, будет принята с благодарностью.

РЕДАКТИРОВАТЬ: - Эта часть была опубликована как новый вопрос:

xslt выберите родительский узел в зависимости от значения атрибута своего внукового узла

Выбор узла с использованием предложений снизу работал. Спасибо! Тем не менее, мне также нужно проверить по атрибуту узла прародителя или внука.

Я пробовал:

<xsl:template name"one" match="grandparentnode">
 <Tag1>
  <xsl:apply-templates select="parentNode" />
 </Tag1>
</xsl:template>

<xsl:template name="two" match="grandparentnode[*/*/@grandchildattr='attrValue']">
 <Tag2>
     <xsl:apply-templates select="parentNode" />
 </Tag2>
</xsl:template>

Однако шаблон "два" всегда вызывается, а "" всегда вставляется. Даже для узлов внуков, значение атрибута которых не равно attrValue.

Я что-то здесь упускаю?

2 ответа

Решение

Я пытался использовать:

<xsl:call-template name="grandparent" select="parent::parent::node()"/> 

а также:

<xsl:call-template name="grandparent" select="ancestor::node[@nameofgrandparentnode]"/>

Но ни один не работает.

Конечно, это не будет "работать", потому что <xsl:call-template> инструкция не имеет select атрибут!

Вы можете передать параметры используя <xsl:with-param> дети <xsl:call-template> инструкция, как это:

<xsl:call-template name="compute">
  <xsl:param name="pAncestor" select="someExpression"/>
</xsl:call-template>

Для select атрибут <xsl:with-param> Используйте:

Для настоящего деда:

../..

для ближайшего предка элемента с именем someName:

ancestor::someName[1]

для ближайшего элемента предка с именем, содержащимся в переменной $ancName:

ancestor::*[name()=$ancName][1]

Я нахожусь в ситуации, когда я могу тестировать только дочерний узел, но я должен применить теги к прародителю этого дочернего узла.

XSLT не является процедурным программированием, поэтому вы должны думать о вещах немного по-другому.

Если я правильно понимаю, вы хотите добавить новые теги (дополнительные дочерние элементы или атрибуты?) В ваш XML, но вы хотите добавить его к предку, когда найдете конкретного потомка. Ваш пример кода, кажется, пытается нацелить бабушку и дедушку, когда вы сталкиваетесь с ребенком. К сожалению, это может быть слишком поздно.

Возможно, вам понадобится внедрить новый элемент / атрибут, когда движок натолкнется на элемент, который вы хотите изменить (прародитель в вашем случае), а не когда он встретит дочерний элемент, который соответствует условию (иначе вы в конечном итоге добавите элементы или атрибуты ребенку)

Рассмотрим этот ввод (grandparent="album", grandchild="label"):

<?xml version="1.0" encoding="UTF-8"?>

<album> 
  <title>Sgt. Pepper's Lonely Hearts Club Band</title>  
  <artist>The Beatles</artist>  
  <year>1967</year>  
  <labels> 
    <label>Parlophone</label>  
    <label>Capitol</label> 
  </labels> 
</album>

Я хочу изменить album на основе того, является ли определенный label настоящее. Помните, что общий формат для таргетинга на узлы: target-node[target-condition], Чтобы изменить любой album элементы, которые имеют Capitol обозначить элемент внука, я бы использовал это:

album[*/label='Capitol']

Так что рассмотрите эту таблицу стилей, чтобы добавить новый атрибут и 2 новых дочерних элемента в albumЭто соответствует моему состоянию:

<?xml version="1.0" encoding="UTF-8"?>

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

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

  <xsl:template match="album[*/label='Capitol']"> 
    <xsl:copy> 
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="new-attribute">A Capitol Record</xsl:attribute>  
      <new-element1/> 
      <xsl:apply-templates select="node()"/>  
      <new-element2/> 
    </xsl:copy> 
  </xsl:template> 

</xsl:stylesheet>

Вывод (отформатированный вручную):

<?xml version="1.0" encoding="UTF-8"?>
<album new-attribute="A Capitol Record"> 
  <new-element1/> 
  <title>Sgt. Pepper's Lonely Hearts Club Band</title>  
  <artist>The Beatles</artist>  
  <year>1967</year>  
  <labels> 
    <label>Parlophone</label>  
    <label>Capitol</label> 
  </labels> 
  <new-element2/>
</album>

Некоторые тестовые ресурсы для песочницы:

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