从下面的示例输入和相应的输出中,我需要一个XSL转换,只跳过<dateline>
父标记下<body>
字段的第一次出现。
<!--Given sample Input XML: -->
<content>
<data>
<datatext>
<message name="message">
<p>Test message paragraph.
<dateline name="dateline">Message datelines</dateline>?
<annotation type="note">Test message Note.</annotation>
</p>
</message>
<head name="head">
<p>Test Head paragraph <annotation type="note">Head notes </annotation> paragraph.
<dateline name="dateline">Head dateline</dateline>
</p>
</head>
<body name="body">
<p>
Test first Body paragraph.
<annotation type="note">First Body notes.</annotation>
</p>
<p>Test Second Body paragraph.</p>
<p>
<annotation type="note">Second Body notes.</annotation>
Test third Body paragraph.
<dateline name="dateline">SECOND DATELINE</dateline>
</p>
<p>Test Fouth Body paragraph.</p>
<p>
<dateline name="dateline">THIRD DATELINE</dateline>
Test fourth Body paragraph.
<annotation type="note">Third Body notes.</annotation>
</p>
</body>
</datatext>
</data>
</content>
应删除预期输出,<dateline>
标记的第一次出现,
<!-- Expected Output XML -->
<content>
<data>
<datatext>
<message name="message">
<p>Test message paragraph.
<dateline name="dateline">Message datelines</dateline>?
<annotation type="note">Test message Note.</annotation>
</p>
</message>
<head name="head">
<p>Test Head paragraph <annotation type="note">Head notes </annotation> paragraph.
<dateline name="dateline">Head dateline</dateline>
</p>
</head>
<body name="body">
<p>
Test first Body paragraph.
<annotation type="note">First Body notes.</annotation>
</p>
<p>Test Second Body paragraph.</p>
<p>
<annotation type="note">Second Body notes.</annotation>
Test third Body paragraph.
</p>
<p>Test Fouth Body paragraph.</p>
<p>
<dateline name="dateline">THIRD DATELINE</dateline>
Test fourth Body paragraph.
<annotation type="note">Third Body notes.</annotation>
</p>
</body>
</datatext>
</data>
</content>
答案 0 :(得分:1)
仅跳过第一次出现的
<dateline>
字段<body>
父标记
首先,body
是dateline
的祖先,而不是父。
现在,由于您要复制除一个节点以外的所有内容,因此最好从身份转换模板(复制所有内容)开始作为规则,并为相关节点添加例外:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body//dateline[generate-id()=generate-id(ancestor::body/descendant::dateline[1])]"/>
</xsl:stylesheet>
为什么必须这么复杂:
为了选择 dateline
的第一个body
后代,您必须使用以下表达式:
body/descendant::dateline[1]
而不是:
body//dateline[1]
中对此进行了解释
注意:位置路径
//para[1]
不与位置路径/descendant::para[1]
的含义相同。后者选择第一个 后代para
元素;前者选择所有后代para
这些元素是父母的第一个para
子女。
然而,表达式:
body/descendant::dateline[1]
不是有效的匹配模式。虽然模式可以使用//运算符,但它们不能使用后代轴:https://www.w3.org/TR/xslt/#patterns
因此,我选择匹配dateline
的后代的任何 body
,并添加一个谓词,用于比较唯一ID当前dateline
与真正是祖先descendant
的第一个body
的{{1}}。这是有效的,因为谓词中允许后代轴 。
答案 1 :(得分:0)
这是一个可能的解决方案。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="bdl" select="//body//dateline"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="dateline[index-of($bdl,.) = 1]"/>
</xsl:stylesheet>
起初我以为你可以只用
<xsl:template match="//body//dateline[1]"/>
但是这不起作用,因为[1]
谓词依赖于焦点和上下文,并且正文中的两个dateline
标记首先位于其直接父级之下。此解决方案首先构建所有正文dateline
标记的序列(在$bdl
中),然后仅删除与列表中第一个条目匹配的标记。
可能有更好的&#34;或更多惯用的方法来实现这一点,我希望其中一位XSLT大师也会回答。