在identity transform中,我们可以通过
删除属性<xsl:template match="@myAttrib"/>
这适用于任何输入...我们可以&#34;替换&#34;带有
的元素的属性<xsl:template match="@myAttrib"><b>my new element</b></xsl:template>
...但仅当输入只有一个属性时才有效。
另一方面,如果我需要替换属性的值,xsl:template
行为是相同的,即
<xsl:template match="@myAttrib">newValue</xsl:template>
不替换值,但删除属性并包含&#34; newValue&#34;作为textNode。
编辑(解释&#34;两个属性&#34;),假设输入
<root>
<parent myAttrib1="1" myAttrib2="2">
<child myAttrib="1" myAttrib3="1"/>
</parent>
<sibling myAttrib0="1"/>
</root>
只有兄弟元素才有一个属性。
答案 0 :(得分:1)
很难回答你的问题,因为你的一些假设是错误的。例如:
<xsl:template match="@myAttrib"><b>my new element</b></xsl:template>
适用于任意数量的元素。将(与身份转换模板一起)应用于以下输入时:
<root>
<parent myAttrib="1">
<child myAttrib="1"/>
</parent>
<sibling myAttrib="1"/>
</root>
结果将是:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<parent>
<b>my new element</b>
<child>
<b>my new element</b>
</child>
</parent>
<sibling>
<b>my new element</b>
</sibling>
</root>
很明显,你的断言“仅当输入只有一个元素时才起作用”是不正确的。
关于:
<xsl:template match="@myAttrib">newValue</xsl:template>
这不会取代myAttrib
的值,因为模板与属性匹配 - 而不是其值(作为旁边:属性的值是不是节点,不能匹配)。就像以前一样,属性匹配,另一个节点输出到位;首先它是一个元素,现在它是一个文本节点。这是唯一的区别。
“替换过程”是每个元素节点的一个属性节点。
不,那也不是真的。例如,考虑以下输入:
<root>
<parent red="1" green="2">
<child red="1" blue="1"/>
</parent>
<sibling green="1" blue="1"/>
</root>
以及以下模板:
<xsl:template match="@red | @blue">
<new/>
</xsl:template>
或:
<xsl:template match="@*[contains(name(), 'r')]">
<new/>
</xsl:template>
-
顺便说一句,这些例子都不适用于撒克逊人 - 但这是另一个故事。
答案 1 :(得分:1)
XSLT模板替换了另一件事。在这种情况下,您将使用文本节点替换属性。如果要将属性替换为具有相同名称但内容不同的其他属性,则可以执行以下操作:
<xsl:template match="@myAttrib">
<xsl:attribute name="{name()}">newValue</xsl:attribute>
</xsl:template>
见上文。 XSLT模板将一件事替换为另一件事。
这可能会在某些情况下导致错误。它不会自动出错。
在添加了其他节点类型之后,XSLT不允许将属性添加到输出流中的父元素。据推测,您的案例中发生的事情是:
myAttrib1
替换元素。myAttrib2
复制为新属性。如果在myAttrib2
之后处理myAttrib1
,则会发生错误。 (不保证处理属性的顺序。)
这可能很难解决,但这种方法在某些情况下会起作用:
<xsl:template match="@*[../@myAttrib]" />
<xsl:template match="@myAttrib">
<xsl:copy-of select="../@*[(. | current())[2]]" />
<b>my new element</b>
</xsl:template>
答案 2 :(得分:0)
从迈克尔的回答(@ michael.hor257k)和我在那里的评论中将我理解的内容翻译给另一位读者;谢谢迈克尔!
假设您有一个输入XML,
<root>
<parent A="1" B="2">
<child C="1" D="1" E="0"/>
</parent>
<sibling E="1">text1</sibling>
</root>
这是内部DOM表示的图表,即树:
root / \ parent sibling / \ \ \ (A,B) child (E) [text1] \ (C,D,E)
元素root
是节点,元素parent
是节点,属性@A
是节点等。文本也是节点...但不是全部tree-itens是节点:图中的一些itens是括号,因为它们是属性节点的集合。
在图中,集合是树项,属性不是。我们可以想象删除或替换树的项目的过程。
“删除节点”任务适用于其XPath指向的任何单个节点。
我们可以想象“删除项目”任务(参见图表),并通过XPath指向项目。
要删除集合项,XPath必须指向集合的所有节点,因此parent/@*
会使项目有效,但parent/@A
不会(因为域parent/@B
)。 XPath sibling/@E
指向集合,因为sibling
元素只有一个属性。 XPath @E
指向两个节点,一个表征集合,另一个不表示。
任务“按文字替换项目X”或“按元素替换项目X”需要指向项目X的XPath。只能替换树形图标。要替换集合项,XPath必须指向集合的所有节点。
总结:属性集合是项目,而不是属性节点;这就是要点(!),并且出现混乱。
在DOM表示中,我们可以访问 nodeValue属性,对于元素和属性,我们可以在两种情况下都改变它:这是另一个混乱的来源,因为这个“改变<的概念em> nodeValue属性“在XSLT中不存在。
所以,
为什么“替换值”无效?
XPath sibling/@E
指向节点属性E
。我们需要类似sibling/@E/nodeValue()
之类的东西来指出值并替换它,但这种XPath不存在。
(编辑)重要提示:如xsl:attribute
所示,使用{{1}},请参阅本页中@ JLRishe的回答。
为什么“替换为元素”不是错误?
概念是“用其他项目替换项目”。当我们看到“项目树”的图表时有意义。
想象“按元素替换节点”是错误的,因为想象“节点树”是错误的,而通用XPath节点可以是具有多个成员的集合的属性。
为什么在“两个属性(每个元素)上下文”中“替换为元素”是一个错误?
因为具有多个属性的集合的单个属性的XPath,不代表集合。 XPath必须指向集合的所有属性,以便在替换过程中使用。