Используйте XSLT для преобразования XML с помощью условных выражений на количество узлов - PullRequest
3 голосов
/ 18 марта 2012

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

<root>
  <branch>
    <foo>bar</foo>
  </branch>
<root>

должно преобразоваться в

  <branch>
  </branch>

но

<root>
  <branch>
    <foo>bar</foo>
  </branch>
  <branch>
    <foo>baz</foo>
<root>

в

<root>
  <branch>
  </branch>
  <branch>
  </branch>
<root>

То есть корневой элемент должен быть удален, если его (единственный) дочерний элемент может выступать в качестве нового корневого документа документа XML результата после применения XSLT. <foo> узлы должны быть удалены в каждом случае.

Есть ли способ выполнить эту операцию с одним XSL?

Ответы [ 2 ]

2 голосов
/ 18 марта 2012

Более простое, короткое и универсальное решение (без указания имен элементов) :

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

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

 <xsl:template match="/*[not(*[2])]">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="/*/*/node()"/>
</xsl:stylesheet>

, когда это преобразование применяется к первому предоставленному XML-документу (исправлено, чтобы быть правильно сформированным):

<root>
    <branch>
        <foo>bar</foo>
    </branch>
</root>

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

<branch></branch>

Когда то же самое преобразованиеприменяется ко второму предоставленному XML-документу (снова необходимо исправить для корректности):

<root>
    <branch>
        <foo>bar</foo>
    </branch>
    <branch>
        <foo>baz</foo>
    </branch>
</root>

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

<root>
    <branch></branch>
    <branch></branch>
</root>

Объяснение :

  1. Правило идентификации копирует каждый узел "как есть".

  2. Существует два шаблона, которые переопределяют шаблон идентификации для определенных узлов и обрабатывают эти узлы по-разному.

  3. Первый переопределяющий шаблон соответствует верхнемуэлемент, который не имеет второго дочернего элемента.Он не копирует сам элемент, а обрабатывает его дочерние элементы.

  4. Второй переопределяющий шаблон соответствует любому элементу, являющемуся потомком верхнего элемента.Этот шаблон не имеет тела, что означает, что все такие совпадающие элементы игнорируются и не включаются в вывод (другими словами - «удалены»)

Doпримечание :

Это преобразование может быть применено к любому XML-документу независимо от имен элементов в нем и по-прежнему дает требуемый, правильный результат.

Например, , при применении к этому документу XML:

<t>
    <b>
        <f>brrr</f>
    </b>
    <b>
        <f>bzzz</f>
    </b>
</t>

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

<t>
    <b></b>
    <b></b>
</t>

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

<t>
    <b>
        <f>brrr</f>
    </b>
    <b>
        <f>bzzz</f>
    </b>
</t>
2 голосов
/ 18 марта 2012

Попробуйте

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

<xsl:template match="root[*[2]]">
  <xsl:copy>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="root[* and not(*[2])]">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="branch/foo"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...