Предок и потомок XPath в XSL-копии - PullRequest
5 голосов
/ 01 июня 2010

Я новичок в XPath, и из того, что я прочитал в некоторых уроках об осях, мне все еще интересно, как их реализовать. Они ведут себя не совсем так, как я ожидал. Мне особенно интересно использовать оси предков и потомков.

У меня есть следующая структура XML:

<file>
    <criteria>
        <root>ROOT</root>
        <criterion>AAA</criterion>
        <criterion>BBB</criterion>
        <criterion>CCC</criterion> 
    </criteria>
    <format>
        <sort>BBB</sort>
    </format>
</file>

И у меня есть следующий XSL:

<xsl:template match="/">
    <xsl:copy-of select="ancestor::criterion/>
</xsl:template>

, который ничего не производит!

Я ожидал, что это произведет:

<file>
    <criteria>
    </criteria>
</file>

Может ли кто-нибудь объяснить мне оси предков и потомков более полезным способом, чем уроки, которые я читал ранее?

Спасибо!

Ответы [ 2 ]

5 голосов
/ 02 июня 2010

И у меня есть следующий XSL:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template>

, который ничего не производит!

Как и положено!

ancestor::criterion

является относительным выражением, что означает, что оно вычисляется вне текущего узла (соответствует шаблону). Но текущим узлом является узел документа /.

Итак, вышесказанное эквивалентно:

/ancestor::criterion

Однако по определению узел документа / не имеет родителей (а это означает, что нет предков), поэтому это выражение XPath не выбирает ни одного узла.

Я ожидал, что это произведет:

<file> 
    <criteria> 
    </criteria> 
</file>

То, что вы, вероятно, хотели, было:

//criterion/ancestor::*

или

//*[descendant::criterion]

Последние два выражения XPath эквивалентны и выбирают все элементы с потомком criterion.

Наконец, для получения желаемого результата, вот одно из возможных решений:

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

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

 <xsl:template match="root | criterion | format"/>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному XML-документу, создается требуемый вывод :

<file>
<criteria>
</criteria>
</file>
1 голос
/ 01 июня 2010

ancestor - для выбора узлов, которые находятся выше (ближе к корню) в документе XML. descendant - для выбора узлов, которые находятся ниже (дочерние) в документе XML.

В вашем примере ancestor::criterion ничего не выбирает, потому что текущий узел - / (в данном случае это означает корень документа - <file>), как указано match="/". Корневой узел не имеет предков, поэтому ось ancestor ничего не делает.

Чтобы получить каждый элемент <criterion>, вы должны использовать ось descendant:

<xsl:template match="/">
  <xsl:copy-of select="descendant::criterion"/>
</xsl:template>

Или его ярлык //:

<xsl:template match="/">
  <xsl:copy-of select="//criterion"/>
</xsl:template>

Это вернет следующее:

<criterion>AAA</criterion>

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

<xsl:template match="/">
  <file>
    <xsl:apply-templates select="//criterion"/>
  </file>
</xsl:template>
<xsl:template match="criterion">
  <xsl:copy-of select="."/>
</xsl:template>

Это приведет к следующему:

<file>
  <criterion>AAA</criterion>
  <criterion>BBB</criterion>
  <criterion>CCC</criterion> 
</file>

Если вы хотите получить элемент <file>, это немного сложнее. XPath определяет узлы, и простые копии не будут копировать элементы, которые содержат выбранные вами элементы. Я могу уточнить этот момент, если вы все еще в замешательстве.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...