我需要创建一个XSLT来遵循两个规则(按优先级顺序):
/xs:schema/node()
以“prefix_”开头的整个/xs:schema/node()/@name
。此/xs:schema/node()
应包含所有后代和属性。/xs:schema/node()
包含 后代任何属性,以“prefix _”开头我遵循此格式的文件
<?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>
答案 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')]) > 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')]) > 0]">
<xsl:copy>
<xsl:apply-templates select="@*|node()[descendant-or-self::*[count(@*[starts-with(., 'prefix')]) > 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')]) > 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">
及其完整子树,或者丢失一些属性。