Xslt 如何解析特定的第一个子级<;日期线>;父标记的标记数据<;车身>;使用XSL 1.0并跳过输出中的值

Xslt 如何解析特定的第一个子级<;日期线>;父标记的标记数据<;车身>;使用XSL 1.0并跳过输出中的值,xslt,xslt-1.0,Xslt,Xslt 1.0,从下面的示例输入和相应的输出中,我需要一个XSL转换来跳过父标记下第一次出现的字段 <!--Given sample Input XML: --> <content> <data> <datatext> <message name="message">

从下面的示例输入和相应的输出中,我需要一个XSL转换来跳过父标记下第一次出现的
字段

       <!--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>

测试消息段落。
消息日期线?
测试消息注释。

测试标题段落标题注释段落。 首部日线

测试第一段正文。 第一个正文注释。

测试第二段正文

第二个正文注释。 测试第三段。 第二条日期线

测试第四段正文

第三条日期线 测试正文第四段。 第三个机构的说明。

预期输出,
标记的第一次出现应被删除

        <!-- 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>

测试消息段落。
消息日期线?
测试消息注释。

测试标题段落标题注释段落。 首部日线

测试第一段正文。 第一个正文注释。

测试第二段正文

第二个正文注释。 测试第三段。

测试第四段正文

第三条日期线 测试正文第四段。 第三个机构的说明。


这里有一个可能的解决方案

<?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]
谓词是焦点和上下文相关的,并且主体中的
日期行
标记首先位于其直接父项下。此解决方案首先构建一个包含所有body
日期行
标记的序列(在
$bdl
中),然后仅删除与列表中第一个条目匹配的一个

可能有一种“更好”或更惯用的方法来实现这一点,我希望XSLT大师之一也会回答这个问题

仅跳过下中第一次出现的
字段
父标记

首先,
body
dateline
祖先,而不是父方

现在,由于您希望复制除一个节点外的所有内容,因此最好从identity transform模板(复制所有内容)开始作为规则,并为相关节点添加一个例外:

XSLT1.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> 
而不是:

body//dateline[1]
下文对此进行了解释:

注意:位置路径
//para[1]
与位置路径
/genderant::para[1]
的含义不同。后者选择前者 后代
para
元素;前者选择所有子体
para
作为其父级的第一个子级的元素

然而,表达方式:

body/descendant::dateline[1]
body/descendant::dateline[1]
不是有效的匹配模式。尽管模式可以使用//运算符,但它们不能使用子体轴:


因此,我选择将任何
日期行
匹配为
主体
的后代,并添加一个谓词,将当前
日期行
的唯一id与祖先
主体
的第一个
后代
进行比较。这是因为谓词中允许使用子代轴。

测试第一个正文段落。第一个正文注释。

测试第二段正文。

测试第三段正文。第二个正文注释。第三个日期行测试第四个正文段落。第三个机构的说明。

这个问题被标记为
xslt-1.0
index-of()
函数需要XSLT 2.0。