XSLT: удалить все, кроме первого вхождения данного узла - PullRequest
2 голосов
/ 12 октября 2009

У меня есть XML примерно так:

<MyXml>  
  <RandomNode1>  
    <TheNode>  
      <a/>  
      <b/>  
      <c/>  
    </TheNode>  
  </RandomeNode1>  
  <RandomNode2>  
  </RandomNode2>  
  <RandomNode3>  
    <RandomNode4>  
      <TheNode>  
        <a/>  
        <b/>  
        <c/>  
      </TheNode>    
    </RandomNode4>  
  </RandomNode3>  
</MyXml>

Где <TheNode> присутствует во всем XML, но не на том же уровне, часто глубоко внутри других узлов. Что мне нужно сделать, это устранить все вхождения <TheNode> за исключением первого. Остальные излишни и занимают место. Что бы XSL мог это сделать?

У меня есть что-то вроде этого:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  
  <xsl:output method="xml" indent="yes"/>  

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

  <xsl:template match="//TheNode[position()!=1]">
  </xsl:template>

</xsl:stylesheet>

Но это не правильно. Есть предложения?

Ответы [ 3 ]

4 голосов
/ 12 октября 2009
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="TheNode[preceding::TheNode]"/>
</xsl:stylesheet>
2 голосов
/ 13 октября 2009

//TheNode[position()!=1] не работает, потому что здесь position() относится к родительскому контексту каждого <TheNode>. Он выберет все <TheNode> s, которые не являются первыми в пределах их соответствующих родителей.

Но вы были на правильном пути. Что вы имели в виду было:

(//TheNode)[position()!=1]

Обратите внимание на круглые скобки - они заставляют предикат применяться ко всему выбранному набору узлов, а не к каждому узлу в отдельности.

К сожалению, даже если это допустимое выражение XPath, оно недопустимо в качестве шаблона соответствия. Шаблон соответствия должен быть значимым (применимым) к отдельному узлу, он не может быть выражением выбора.

Итак, @ решение Алохчи,

//TheNode[preceding::TheNode]

- это правильный способ выразить то, что вы хотите.

0 голосов
/ 24 января 2011

Другой подход для шаблона будет:

<xsl:template match="TheNode[generate-id()
                             != generate-id(/descendant::TheNode[1)]"/>

Примечание : более вероятно, что абсолютное выражение получает оптимизированные целые числа относительного выражения, например preceding::TheNode

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