2

XSL 很难。我在这里的问题的答案让我大部分都走上了正确的轨道,但是我最初忽略了一些小事情。这是我最近的尝试:

XSL:

<!--
    When a file is transformed using this stylesheet the output will be
    formatted as follows:

    1.)  Elements named "info" will be removed
    2.)  Attributes named "file_line_nr" or "file_name" will be removed
    3.)  Comments will be removed
    4.)  Processing instructions will be removed
    5.)  XML declaration will be removed
    6.)  Extra whitespace will be removed
    7.)  Empty attributes will be removed
    8.)  Elements void of both attributes and child elements will be removed
    9.)  All elements will be sorted by name recursively
    10.) All attributes will be sorted by name
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <!--
        Elements/attributes to remove.  Note that comments are not elements or
        attributes.  Since there is no template to match comments they are
        automatically ignored.
    -->
    <xsl:template match="@*[normalize-space()='']|info|@file_line_nr|@file_name"/>

    <!-- Match any attribute -->
    <xsl:template match="@*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
        </xsl:copy>
    </xsl:template>

    <!-- Match any element -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="@*">
                <xsl:sort select="name()"/>
            </xsl:apply-templates>
            <xsl:apply-templates>
                <xsl:sort select="name()"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

我想我已经解决了除第 8 项之外的所有要求。我可以成功地制作一个样式表来删除没有子元素的元素,或者删除没有属性的元素,但这不是我想要的。我只想删除没有属性、子元素或文本的元素。

输入 XML:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?><!-- XML declaration should be removed -->
<foo b="b" a="a" c="c">
    <?some-app inst="some instruction"?><!-- Processing instructions should be removed -->
    <qwer><!-- Keep elements like this because it has child elements -->
        <zxcv c="c" b="b"/><!-- Keep elements like this because it has attributes -->
        <id>some text</id><!-- Keep elements like this because it has text -->
        <info i="i"/><!-- Elements named "info" are to be removed -->
        <rewq file_line_nr="42" file_name="somefile.txt"/><!-- Attributes named "file_line_nr" and "file_name" are to be removed which will leave this element empty, so it should be removed too -->
        <vcxz c="c" b="b"/>
    </qwer>
    <baz e="e" d="d"/>
    <bar>
        <fdsa g="g" f="f"/>
        <asdf g="g" f="f"/>
    </bar>
</foo>

所需的输出 XML:(无注释、无空格/缩进、元素和属性已排序)

<foo a="a" b="b" c="c">
<bar>
<asdf f="f" g="g"/>
<fdsa f="f" g="g"/>
</bar>
<baz d="d" e="e"/>
<qwer>
<id>some text</id>
<vcxz b="b" c="c"/>
<zxcv b="b" c="c"/>
</qwer>
</foo>
4

2 回答 2

1

这应该做的工作:

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

  <!--
        Elements/attributes to remove.  Note that comments are not elements or
        attributes.  Since there is no template to match comments they are
        automatically ignored.
    -->
  <xsl:template match="@*[normalize-space()='']|info|@file_line_nr|@file_name"/>

  <!-- Match any attribute -->
  <xsl:template match="@*">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
    </xsl:copy>
  </xsl:template>

  <!-- Match any element -->
  <xsl:template match="*">
    <xsl:variable name="elementFragment">
      <xsl:copy>
        <xsl:apply-templates select="@*">
          <xsl:sort select="name()"/>
        </xsl:apply-templates>
        <xsl:apply-templates>
          <xsl:sort select="name()"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:variable>
    <xsl:variable name="element" select="msxsl:node-set($elementFragment)/*"/>
    <xsl:if test="$element/@* or $element/* or normalize-space($element)">
      <xsl:copy-of select="$element"/>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

这个想法是对元素进行预处理,将结果放入变量中,然后对变量执行“元素没有属性、子元素或文本”测试。

该变量是一个 XML 片段,需要使用扩展函数将其转换为节点集 - 我的 XSLT 使用 Microsoft 的msxsl:node-set- 其他处理器具有等效功能。

于 2013-09-11T15:17:06.110 回答
0

最简单的方法是制定一个禁止对所有元素进行处理的规则:

<xsl:template match="*"/>

然后遵循一个规则,匹配具有一个属性或子元素的元素:

<xsl:template match="*[attribute:*] | *[child::*]">
    ...process...
</xsl:template>

或者,如果您愿意

match="*[@*] | *[*]"
于 2013-09-11T16:39:45.107 回答