XSLT: переместить узел на один уровень вверх - PullRequest
8 голосов
/ 24 января 2011

Я хотел бы знать, как переместить узлы на один уровень выше, используя XSLT, если выполняются определенные условия.Чтобы привести пример, взгляните на следующий источник XML:

<Settings>
  <String [...]>
    <Boolean [...]/>
  </String>
</Settings>

Это XML, который у меня есть в качестве исходной ситуации.Для ясности, имена узлов «Settings», «String», «Boolean» являются особыми узлами, которые мы определили.

Проблема в том, что логические узлы не допускаются внутри узлов «String».Вот почему я должен переместить эти "логические" узлы на уровень выше.Требуемый XML будет выглядеть следующим образом:

<Settings>
  <String [...]></String>
  <Boolean [...]/>
</Settings>

XSLT также должен работать с каждым узлом String, у которого есть родственный логический узел, независимо от позиции в дереве XML.

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

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"        
  xmlns:fo="http://www.w3.org/1999/XSL/Format" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:fn="http://www.w3.org/2005/xpath-functions">

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

  <!-- special rules ... -->

</xsl:stylesheet>

То, с чем я борюсь, это правило дляпереместить все "логические" узлы, которые являются родственными узлами "строковых" узлов на один уровень вверх.Как я могу это сделать?!?

Ответы [ 3 ]

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

Моя интерпретация требования дает решение как

<?xml version="1.0" encoding="UTF-8"?>
<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="String">
    <xsl:copy>
        <xsl:apply-templates select="child::node()[not(self::Boolean)]"/>
    </xsl:copy>
    <xsl:apply-templates select="Boolean"/>
</xsl:template>

</xsl:stylesheet>
3 голосов
/ 24 января 2011

Это решение очень похоже на решение @ Michae-Kay.Однако переопределение правила идентификации немного более точно - сопоставляются только элементы String, которые действительно имеют дочерний элемент Boolean:

<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="String[Boolean]">
  <xsl:copy>
    <xsl:apply-templates select="node()[not(self::Boolean)]|@*"/>
  </xsl:copy>
  <xsl:apply-templates select="Boolean"/>
 </xsl:template>
</xsl:stylesheet>

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

<Settings>
    <String>
        <Boolean />
    </String>
    <String/>
</Settings>

желаемый, правильный результат получается :

<Settings>
   <String/>
   <Boolean/>
   <String/>
</Settings>
3 голосов
/ 24 января 2011

Попробуйте следующее:

<!-- copy all -->
<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>

<!-- ignore booleans-inside-strings -->
<xsl:template match="String/Boolean" />

<!-- place the booleans-inside-strings into the settings element -->
<xsl:template match="Settings">
    <xsl:copy>
        <xsl:copy-of select="//String/Boolean" />
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...