XSLT使用字符串匹配修改身份规则

时间:2011-09-15 15:15:16

标签: xslt xpath xslt-1.0

我需要创建一个XSLT来遵循两个规则(按优先级顺序):

  1. 应复制/xs:schema/node()以“prefix_”开头的整个/xs:schema/node()/@name。此/xs:schema/node()应包含所有后代和属性。
  2. 应创建一个/xs:schema/node()包含 后代任何属性,以“prefix _”开头
  3. 我遵循此格式的文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!--
        this is
        a really long
        comment
        that spans
        multiple lines
    -->
    <!-- <!a comment > another comment -->
    <!-- <!a comment > another comment -->
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified"
        attributeFormDefault="unqualified">
    
        <!-- a comment -->
        <xs:node name="ABC">
            <xs:node>
                <xs:element/>
                <xs:element attr="asdf"/>
            </xs:node>
        </xs:node>
        <!-- <!a comment > another comment -->
        <node name="DEF">
            <element/>
            <element attr="asdf" bttr="zxcv"/>
        </node>
        <!-- <!a comment > another comment -->
        <node name="prefix_a">
            <element/>
            <element attr="asdf"/>
            <element attr="prefix_attr"/>
            <element battr="prefix_battr"/>
        </node>
    
        <node name="prefix_b">
            <node>
                <element/>
                <element battr="prefix_bttr"/>
                <element hattr="prefix_cattr"/>
            </node>
        </node>
    
        <node name="c">
            <node>
                <node>
                    <node>
                        <node>
                            <element attr="qwerty"/>
                            <element attr="zxvc"/>
                            <element attr="asdf"/>
                            <element battr="prefix_bttr"/>
                            <element flattr="prefix_hattr"/>
                        </node>
                    </node>
                </node>
            </node>
        </node>
    
        <node name="d">
            <element/>
            <element attr="asdf"/>
            <element shattr="prefix_shattr"/>
            <element cattr="prefix_battr"/>
        </node>
        <!-- <!a comment > another comment -->
        <node name="g">
            <element attr="asdf" bttr="zxcv"/>
            <element/>
        </node>
    
    </xs:schema>
    

    XSLT应该返回;

    <xml>
    <xs:schema>
    
      <node name="prefix_a">
        <element />
        <element attr="asdf" />
        <element attr="prefix_attr" />
        <element battr="prefix_battr" />
      </node>
    
      <node name="prefix_b">
        <node>
          <element />
          <element battr="prefix_bttr" />
          <element hattr="prefix_cattr" />
        </node>
      </node>
    
      <node name="c">
        <node>
          <node>
            <node>
              <node>
                <element battr="prefix_bttr" />
                <element flattr="prefix_hattr" />
              </node>
            </node>
          </node>
        </node>
      </node>
    
      <node name="d">
        <element shattr="prefix_shattr" />
        <element cattr="prefix_battr" />
      </node>
    
    </xs:schema>
    

    我在下面使用以下XSLT;

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    
        <xsl:namespace-alias stylesheet-prefix="xs" result-prefix="xsd"/>
    
        <xsl:output method="xml" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:template match="/">
            <xsl:apply-templates select="xsd:schema"/>
        </xsl:template>
    
        <xsl:template match="xsd:schema">
            <xs:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified"
                attributeFormDefault="unqualified" version="1.0">
                <xsl:apply-templates select="node()[starts-with(@name, 'prefix_')]"/>
                <xsl:apply-templates select="node()[descendant::node()/@*[starts-with(., 'prefix_')]]"/>
            </xs:schema>
        </xsl:template>
    
        <xsl:template match="xsd:schema/node()[starts-with(@name, 'prefix_')]">
            <xsl:copy-of select="current()"/>
        </xsl:template>
    
        <xsl:template match="xsd:schema/node()[descendant::node()/@*[starts-with(., 'prefix_')]]">
            <xsl:copy-of select="current()"/>
        </xsl:template>
    
    
    </xsl:stylesheet>
    

3 个答案:

答案 0 :(得分:2)

我修复了@Dimitre注意到的愚蠢错误。

现在,进行以下转换:

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

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

    <xsl:template match="xs:schema/*[
        not(starts-with(@name,'prefix_'))
            and
            not(.//*/@*[starts-with(.,'prefix_')])]"/>

    <xsl:template match="*[
        not(*) 
            and
        not(@*[starts-with(.,'prefix_')])
            and
        not(ancestor::*[starts-with(@name,'prefix_')])
        ]"/>

</xsl:stylesheet>

给出这个输入(略微修改以涵盖更复杂的情况):

<xml>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

        <!-- a comment -->

        <node name="prefix_a">
            <element />
            <element attr="asdf" />
            <element x="y" attr="prefix_attr" />
            <element battr="prefix_battr" y="x"/>
        </node>

        <node name="prefix_b">
            <node>
                <element />
                <element battr="prefix_bttr" />
                <element hattr="prefix_cattr" />
            </node>
        </node>

        <node name="c">
            <node>
                <node>
                    <node>
                        <node>
                            <element attr="qwerty" />
                            <element attr="zxvc" />
                            <element attr="asdf" />
                            <element battr="prefix_bttr" x="y"/>
                            <element flattr="prefix_hattr" y="x"/>
                        </node>
                    </node>
                </node>
            </node>
        </node>

        <node name="d">
            <element />
            <element attr="asdf" />
            <element shattr="prefix_shattr" />
            <element cattr="prefix_battr" />
        </node>

        <node name="e">
            <element />
            <element attr="asdf" />
        </node>

    </xs:schema>
</xml>

产生

<xml>
   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <node name="prefix_a">
         <element/>
         <element attr="asdf"/>
         <element x="y" attr="prefix_attr"/>
         <element battr="prefix_battr" y="x"/>
      </node>
      <node name="prefix_b">
         <node>
            <element/>
            <element battr="prefix_bttr"/>
            <element hattr="prefix_cattr"/>
         </node>
      </node>
      <node name="c">
         <node>
            <node>
               <node>
                  <node>
                     <element battr="prefix_bttr" x="y"/>
                     <element flattr="prefix_hattr" y="x"/>
                  </node>
               </node>
            </node>
         </node>
      </node>
      <node name="d">
         <element shattr="prefix_shattr"/>
         <element cattr="prefix_battr"/>
      </node>
   </xs:schema>
</xml>

答案 1 :(得分:1)

如果节点的 @name 属性以前缀_ 开头,则可以保留标识转换以完成其工作。因此,您只需要覆盖没有以前缀_ 开头的 @name 的元素的大小写。

<xsl:template match="xs:schema/node()[not(starts-with(@name, 'prefix'))]">

要仅复制具有以“prefix_”开头的任何属性的后代,您还需要复制任何可能本身没有属性的节点,但它本身的后代符合条件。

<xsl:apply-templates 
   select="@*|
      node()[descendant-or-self::*[count(@*[starts-with(., 'prefix')]) &gt; 0]]" 
   mode="attr" />

因此,在这里,您在应用模板时使用模式属性,因此您也可以覆盖匹配后代的行为

<xsl:template match="@*|node()" mode="attr">

这是完整的XSLT:

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

   <xsl:template match="/">
      <xsl:apply-templates />
   </xsl:template>

   <xsl:template match="xs:schema/node()[not(starts-with(@name, 'prefix'))]">
      <xsl:if test="descendant-or-self::*[count(@*[starts-with(., 'prefix')]) &gt; 0]">
         <xsl:copy>
            <xsl:apply-templates select="@*|node()[descendant-or-self::*[count(@*[starts-with(., 'prefix')]) &gt; 0]]" mode="attr" />
         </xsl:copy>
      </xsl:if>
   </xsl:template>

   <xsl:template match="@*|node()" mode="attr">
      <xsl:copy>
         <xsl:apply-templates select="@*[starts-with(., 'prefix')]|node()[descendant-or-self::*[count(@*[starts-with(., 'prefix')]) &gt; 0]]" mode="attr"/>
      </xsl:copy>
   </xsl:template>

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

</xsl:stylesheet>

当应用于输入XML时,输出如下:

<xml>
   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <node name="prefix_a">
         <element/>
         <element attr="asdf"/>
         <element attr="prefix_attr"/>
         <element battr="prefix_battr"/>
      </node>
      <node name="prefix_b">
         <node>
            <element/>
            <element battr="prefix_bttr"/>
            <element hattr="prefix_cattr"/>
         </node>
      </node>
      <node name="c">
         <node>
            <node>
               <node>
                  <node>
                     <element battr="prefix_bttr"/>
                     <element flattr="prefix_hattr"/>
                  </node>
               </node>
            </node>
         </node>
      </node>
      <node name="d">
         <element shattr="prefix_shattr"/>
         <element cattr="prefix_battr"/>
      </node>
   </xs:schema>
</xml>

答案 2 :(得分:1)

如果其值以“prefix_”开头的属性不是其父元素的第一个(也是唯一的)属性,则其他两个答案都无法正常工作!

此转换(除了正确似乎是最短和最简单的 - 没有模式,没有明确的条件指令):

<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=
   "node[@name[not(starts-with(.,'prefix_'))]
        and
          not(descendant::*[@*[starts-with(.,'prefix_')]])
         ]"/>

  <xsl:template match=
   "*[ancestor::node[@name[not(starts-with(.,'prefix_'))]]
    and
      not(*)
    and
      not(@*[starts-with(.,'prefix_')])
     ]"/>
</xsl:stylesheet>

应用于以下XML文档(提供的文档,但扩展了以便某些元素具有两个属性 - 请查看<node name="c">):

<xml>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <!-- a comment -->

  <node name="prefix_a">
    <element />
    <element attr="asdf" />
    <element attr="prefix_attr" />
    <element battr="prefix_battr" />
  </node>

  <node name="prefix_b">
    <node>
      <element />
      <element battr="prefix_bttr" />
      <element hattr="prefix_cattr" />
    </node>
  </node>

  <node name="c">
    <node>
      <node>
        <node>
          <node>
            <element attr="qwerty" />
            <element attr="zxvc" />
            <element attr="asdf" />
            <element battr="prefix_bttr" />
            <element flattr="prefix_hattr" />
          </node>
        </node>
      </node>
    </node>
  </node>

  <node name="d">
    <element />
    <element attr="asdf" />
    <element shattr="prefix_shattr" />
    <element cattr="prefix_battr" />
  </node>

  <node name="e">
    <element />
    <element attr="asdf" />
  </node>
</xs:schema>
</xml>

生成想要的正确结果

<xml>
   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"><!-- a comment --><node name="prefix_a">
         <element/>
         <element attr="asdf"/>
         <element attr="prefix_attr"/>
         <element battr="prefix_battr"/>
      </node>
      <node name="prefix_b">
         <node>
            <element/>
            <element battr="prefix_bttr"/>
            <element hattr="prefix_cattr"/>
         </node>
      </node>
      <node name="c">
         <node>
            <node>
               <node>
                  <node>
                     <element y="z" battr="prefix_bttr"/>
                     <element x="y" flattr="prefix_hattr"/>
                  </node>
               </node>
            </node>
         </node>
      </node>
      <node name="d">
         <element shattr="prefix_shattr"/>
         <element cattr="prefix_battr"/>
      </node>
   </xs:schema>
</xml>

请注意,其他两个答案中的解决方案会丢失元素<node name="c">及其完整子树,或者丢失一些属性。

相关问题