Удаление элементов и / или атрибутов по имени для параметров XSL

следующая задача удаления нежелательных элементов и атрибутов по имени ("removeMe" в этом примере) из XML-файла:

<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() | @*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node() | @*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="removeMe"/>
</xsl:stylesheet>

проблемы в том, что он не различает элементы и атрибуты, имя жестко закодировано, и оно может принимать только одно имя. как это можно переписать, чтобы использовать пару входных параметров, как показано ниже, для удаления одного или нескольких конкретных элементов и/или атрибутов?

<xsl:param name="removeElementsNamed"/>
<xsl:param name="removeAttributesNamed"/>

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

хотя я требовал XSLT 1.0 в этом раунде, решения XSLT 2.0 в принятых и других ответах могут быть полезны для другие.

4 ответов


трансформация:

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

 <xsl:param name="removeElementsNamed" select="'x'"/>

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

 <xsl:template match="*">
  <xsl:if test="not(name() = $removeElementsNamed)">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

при применении к любому XML-документу, скажите это:

<t>
    <a>
        <b/>
        <x/>
    </a>
    <c/>
    <x/>
    <d/>
</t>

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


вот опция XSLT 2.0, Если вы можете использовать 2.0. Имена элементов могут передаваться через запятую, вкладку,канал или пробел.

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

  <xsl:param name="removeElementsNamed" select="'bar,baz'"/>  

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

  <xsl:template match="*[name()=tokenize($removeElementsNamed,'[\|, \t]')]"/>  

</xsl:stylesheet>

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

   <xsl:output omit-xml-declaration="yes" indent="yes"/>
   <xsl:param name="removeMe"/>

   <xsl:template match="node() | @*">
      <xsl:if test="not(name(.)=$removeMe)">
        <xsl:copy>
           <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
      </xsl:if>
   </xsl:template>   


</xsl:stylesheet>

Это somehwat hacky, но это может дать вам общее представление:

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

<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="removeElementsNamed"/>

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

<xsl:template match="*[contains($removeElementsNamed, concat(',',name(),','))]"/>

вам нужно указать имена элементов для удаления в виде списка, разделенного запятыми, начиная с запятой и заканчивая запятой, например,значение", foo,bar, baz" удалит все элементы с именем foo bar или baz. Если у вас нет каких-либо элементов, которые являются частичными именами других элементов, вы можете упростить это до:

<xsl:template match="*[contains($removeElementsNamed,name())]"/>

однако, если у вас есть XML, как

<foo>
  <bar>..<bar>
  <barbara>..</barbara>
<foo>

и используйте " bar " в качестве параметра, это удалит теги bar и barbara, поэтому первый подход безопаснее.