如何使用xsl根据属性将xml的兄弟节点更改为父节点和子节点
Posted
技术标签:
【中文标题】如何使用xsl根据属性将xml的兄弟节点更改为父节点和子节点【英文标题】:How to change the siblings of xml into parent and child nodes according to their attributes using xsl 【发布时间】:2021-12-08 12:59:17 【问题描述】:输入是
<p style="abc">hbfg</p>
<r style="cds">bhf</r>
<r style="cds"> bhfsh</r>
<p style="abc">pofj</p>
<r style="abc"> bchs</r>
预期的输出应该是
<p style="abc">hbfg
<r style="cds">bhf</r>
<r style="cds"> bhfsh</r></p>
<p style="abc">pofj
<r style="abc"> bchs</r></p>
如何使用 xslt 进行转换。
【问题讨论】:
请编辑问题以将其限制为具有足够详细信息的特定问题,以确定适当的答案。 如果您format your code 并使用*** 的syntax highlighting,您的问题会更容易阅读/理解。 嗨@Douglas.P 我改变了问题希望你理解我的问题并回答我的问题。在此先感谢:) 【参考方案1】:这里有两个版本的 XSLT 样式表,它们将处理 XML
你发布的文件,一个为xslt-2.0 介绍了一个方便的
xsl:for-each-group group-starting-with=pattern
这个元素
用例,为了最大的可移植性,一个用于xslt-1.0 使用
XPath 进行分组。两个版本都使用doc/text
作为逻辑
树的根和xsl:apply-templates
充分利用
内置模板规则。注意空格处理。
平面文件转换的更多示例在 SO 和 XSLT 1.0 FAQ,现在在 archive.org.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="doc/text">
<chapter>
<title>
<xsl:apply-templates select="p[@style='TRH2']"/>
</title>
<research>
<title>
<xsl:apply-templates select="p[@style='TRRef']"/>
</title>
<reftext>
<xsl:apply-templates select="p[@style='TRRefText']"/>
</reftext>
</research>
<sections>
<xsl:for-each-group
select="p[not(@style) or @style='TRH7']"
group-starting-with="p[@style='TRH7']"
>
<title>
<xsl:apply-templates select="self::p[1]"/>
</title>
<paragraphs>
<xsl:for-each select="current-group()[self::p][position()>1]">
<para-text>
<xsl:apply-templates/>
</para-text>
</xsl:for-each>
</paragraphs>
</xsl:for-each-group>
</sections>
</chapter>
</xsl:template>
<xsl:template match="p[@style='TRRefText']">
<xsl:value-of select="."/><br/>
</xsl:template>
<xsl:template match="foot-note">
<footnoteref>
<id><xsl:value-of select="@id-rel"/></id>
<xsl:apply-templates/>
</footnoteref>
</xsl:template>
</xsl:transform>
XSLT 1.0 版本(在第三个xsl:template
)使用 XPath
将非标题 p
元素分组在当前和之间的表达式
下一个小节标题元素 (p[@style='TRH7']
) 和 mode="para"
子句以避免将标题同时作为标题和段落处理。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="doc/text">
<chapter>
<title>
<xsl:apply-templates select="p[@style='TRH2']" />
</title>
<research>
<title>
<xsl:apply-templates select="p[@style='TRRef']" />
</title>
<reftext>
<xsl:apply-templates select="p[@style='TRRefText'] "/>
</reftext>
</research>
<sections>
<xsl:apply-templates select="p[@style='TRH7']" />
</sections>
</chapter>
</xsl:template>
<xsl:template match="p[@style='TRRefText']">
<xsl:value-of select="."/><br/>
</xsl:template>
<xsl:template match="p[@style='TRH7']">
<title><xsl:apply-templates/></title>
<paragraphs>
<xsl:apply-templates mode="para"
select="following-sibling::p[not(@style='TRH7')]
[generate-id(preceding-sibling::p[@style='TRH7'][1])
= generate-id(current())]"
/>
</paragraphs>
</xsl:template>
<xsl:template match="p" mode="para">
<para-text><xsl:apply-templates/></para-text>
</xsl:template>
<xsl:template match="foot-note">
<footnoteref>
<id><xsl:value-of select="@id-rel"/></id>
<xsl:apply-templates/>
</footnoteref>
</xsl:template>
</xsl:transform>
更新:评论中要求的其他解释。
您自己的代码与我发布的非常接近,因此我将详细介绍如何使用 XSLT 1.0 对元素进行分组。文档中的每个小节都由其标题的样式 (p[@style='TRH7']
) 触发,激活第三个模板:
<xsl:template match="p[@style='TRH7']">
<title><xsl:apply-templates/></title>
<paragraphs>
<xsl:apply-templates mode="para"
select="following-sibling::p[not(@style='TRH7')]
[generate-id(preceding-sibling::p[@style='TRH7'][1])
= generate-id(current())]"
/>
</paragraphs>
</xsl:template>
此模板发出一个小节标题(使用内置模板规则),然后收集以下非标题段落
(following-sibling::p[not(@style='TRH7')]
) 有当前
title 作为最近的逻辑父级。回想一下preceding-sibling
是一个反向轴,所以p[…][1]
指的是反向文档顺序中最近的兄弟。由于following-sibling::p[…]
选择了所有后续的非标题段落,第二个谓词[generate-id(…)]
将选择限制为当前标题的逻辑子项。
【讨论】:
谢谢@urcodebetterznow 它的工作,你能清楚地解释第二个xsl转换吗? @NaveenKumar:我更新了我的回复。另请参阅我链接到的 XSLT 1.0 FAQ 页面中的第 1 项和第 4 项。 HI @urcodebetterznow 我们如何将没有属性的相似节点合并为单个节点。 @NaveenKumar:要选择所有没有属性的p
元素,您可以说<xsl:apply-templates select="//p[not(@*)]"/>
。如果这不是您的想法,我建议您提出一个新问题,包括示例代码。
嗨@urcodebetterznow 我可以得到你的联系方式,以便我可以分享问题并想了解更多关于 xslt 的信息,比如你的邮件 ID 吗?以上是关于如何使用xsl根据属性将xml的兄弟节点更改为父节点和子节点的主要内容,如果未能解决你的问题,请参考以下文章