输入 XML:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<text>
<body>
<head>title1</head>
<div n="1">
<head>title2</head>
<div n="1.1">
<head>title3</head>
<p>xyz</p>
<p>xyz</p>
</div>
<div n="1.2">
<head>title4</head>
<p>xyz</p>
<p>xyz</p>
<div n="1.2.1">
<p>xyz</p>
<p>xyz</p>
</div>
</div>
</div>
</body>
</text>
</Root>
我想为所有 <div>
添加属性“id=1”元素和属性“level=0”到 <div>
其中没有<div>
child 。
这是我实际的 XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()" priority="-1">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body//div">
<xsl:copy>
<xsl:apply-templates select="node()[not(descendant::div)]" mode="level"/>
<xsl:apply-templates select="node()[descendant::div]" mode="id"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body//div[not(descendant::div)]" mode="level">
<xsl:copy>
<xsl:for-each select=".">
<xsl:attribute name="id">1</xsl:attribute>
<xsl:attribute name="level">0</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body//div[descendant::div]" mode="id">
<xsl:copy>
<xsl:for-each select=".">
<xsl:attribute name="id">1</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
模式为“id”的模板应匹配 <div>
具有 <div>
的元素child(添加属性“id”),具有 mode="level"的模板应匹配没有 <div>
的元素child(添加属性“id”和“level”)。但由于某种原因我得到了一些<div>
(n=1 和 n=1.2.1 的那些)没有被任何模板处理。
实际输出 XML:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<text>
<body>
<head>title1</head>
<div>
title2
<div id="1" level="0" n="1.1">
<head>title3</head>
<p>xyz</p>
<p>xyz</p>
</div>
<div id="1" n="1.2">
<head>title4</head>
<p>xyz</p>
<p>xyz</p>
<div>
xyz
xyz
</div>
</div>
</div>
</body>
</text>
</Root>
我很确定我犯了一些奇怪的明显错误(也许是在使用带有模式的模板时?),但到目前为止还没有发现它。任何建议将不胜感激。 谢谢大家。
最佳答案
我不完全确定你为什么要使用模式。下面的解决方案仅使用“通用”模板即可实现您想要的效果。
具有模式的模板专门设计用于多次迭代树,从而访问和处理节点两次或更多次。
作为一项规则,应尽可能少地中断身份转换。这就是为什么下面的样式表匹配
div
元素与div
子元素 (div[div]
)- 没有它们 (
div[not(div)]
),
应用最小的更改,然后使用apply-templates
再次将其余节点返回到身份转换。
注意:这适合您显示的输入 XML。然而,为了使其适用于您的实际输入,您可能必须进行更改
<xsl:template match="div[div]">
至
<xsl:template match="div[descendant::div]">
取决于您的输入结构。
样式表
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[div]">
<xsl:copy>
<xsl:attribute name="id">1</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[not(div)]">
<xsl:copy>
<xsl:attribute name="id">1</xsl:attribute>
<xsl:attribute name="level">0</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<text>
<body>
<head>title1</head>
<div id="1">
<head>title2</head>
<div id="1" level="0">
<head>title3</head>
<p>xyz</p>
<p>xyz</p>
</div>
<div id="1">
<head>title4</head>
<p>xyz</p>
<p>xyz</p>
<div id="1" level="0">
<p>xyz</p>
<p>xyz</p>
</div>
</div>
</div>
</body>
</text>
</Root>
关于xml - 具有模式属性的 XSLT 1.0 模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21139226/