Apply-Template 仅适用于 ID 基于父子节点列表的节点
Posted
技术标签:
【中文标题】Apply-Template 仅适用于 ID 基于父子节点列表的节点【英文标题】:Apply-Template only for nodes with ID based on parent subnode list 【发布时间】:2021-05-27 14:29:51 【问题描述】:我对 XSLT 还很陌生,并试图解决一个复杂的 XML 问题。 这是关于 XML 和所需输出的示例。
问题是我需要根据Order
的IdentityOrder
选择Identity
。比较应该在IdentityId
上完成。
如果身份的LastName
为空,则该订单不应包含在列表中
正如您从我的实验中看到的那样,我可以通过转换来完成这项工作,但我无法弄清楚如何排除 Identity 的 LastName 为空的订单。
感谢我能得到的所有帮助;)
<Orders>
<Order>
<OrderNo>OR1</OrderNo>
<BookingHeader>
<BookingHeaderID>1</BookingHeaderID>
<Identities>
<Identity>
<IdentityId>1</IdentityId>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Identity>
<Identity>
<IdentityId>2</IdentityId>
<FirstName>Petter</FirstName>
<LastName>Smart</LastName>
</Identity>
<Identity>
<IdentityId>3</IdentityId>
<FirstName>Betty</FirstName>
<LastName>Blue</LastName>
</Identity>
</Identities>
</BookingHeader>
<IdentityOrders>
<IdentityOrder>
<IdentityId>1</IdentityId>
<Name>John Doe</Name>
</IdentityOrder>
</IdentityOrders>
</Order>
<Order>
<OrderNo>OR2</OrderNo>
<BookingHeader>
<BookingHeaderID>1</BookingHeaderID>
<Identities>
<Identity>
<IdentityId>1</IdentityId>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Identity>
<Identity>
<IdentityId>2</IdentityId>
<FirstName>Petter</FirstName>
<LastName>Smart</LastName>
</Identity>
<Identity>
<IdentityId>3</IdentityId>
<FirstName>Betty</FirstName>
<LastName>Blue</LastName>
</Identity>
</Identities>
</BookingHeader>
<IdentityOrders>
<IdentityOrder>
<IdentityId>1</IdentityId>
<Name>John Doe</Name>
</IdentityOrder>
<IdentityOrder>
<IdentityId>3</IdentityId>
<Name>Betty Blue</Name>
</IdentityOrder>
</IdentityOrders>
</Order>
<Order>
<OrderNo>OR3</OrderNo>
<BookingHeader>
<BookingHeaderID>1</BookingHeaderID>
<Identities>
<Identity>
<IdentityId>1</IdentityId>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Identity>
<Identity>
<IdentityId>2</IdentityId>
<FirstName>Petter</FirstName>
<LastName></LastName>
</Identity>
<Identity>
<IdentityId>3</IdentityId>
<FirstName>Betty</FirstName>
<LastName>Blue</LastName>
</Identity>
</Identities>
</BookingHeader>
<IdentityOrders>
<IdentityOrder>
<IdentityId>2</IdentityId>
<Name>Petter</Name>
</IdentityOrder>
<IdentityOrder>
<IdentityId>3</IdentityId>
<Name>Betty Blue</Name>
</IdentityOrder>
</IdentityOrders>
</Order>
<Order>
<OrderNo>OR4</OrderNo>
<BookingHeader>
<BookingHeaderID>2</BookingHeaderID>
<Identities>
<Identity>
<IdentityId>4</IdentityId>
<FirstName>Roger</FirstName>
<LastName>Moore</LastName>
</Identity>
<Identity>
<IdentityId>5</IdentityId>
<FirstName>Sylvester</FirstName>
<LastName></LastName>
</Identity>
<Identity>
<IdentityId>6</IdentityId>
<FirstName>Arnold</FirstName>
<LastName></LastName>
</Identity>
</Identities>
</BookingHeader>
<IdentityOrders>
<IdentityOrder>
<IdentityId>4</IdentityId>
<Name>Roger Moore</Name>
</IdentityOrder>
<IdentityOrder>
<IdentityId>5</IdentityId>
<Name>Sylvester</Name>
</IdentityOrder>
</IdentityOrders>
</Order>
</Orders>
改造后想要的结果
<?xml version="1.0" encoding="utf-8"?>
<Orders>
<Order>
<OrderNo>OR1</OrderNo>
<Identities>
<Identity>
<IdentityId>1</IdentityId>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Identity>
</Identities>
</Order>
<Order>
<OrderNo>OR2</OrderNo>
<Identities>
<Identity>
<IdentityId>1</IdentityId>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
</Identity>
<Identity>
<IdentityId>3</IdentityId>
<FirstName>Betty</FirstName>
<LastName>Blue</LastName>
</Identity>
</Identities>
</Order>
<Order>
<OrderNo>OR3</OrderNo>
<Identities>
<Identity>
<IdentityId>3</IdentityId>
<FirstName>Betty</FirstName>
<LastName>Blue</LastName>
</Identity>
</Identities>
</Order>
<Order>
<OrderNo>OR4</OrderNo>
<Identities>
<Identity>
<IdentityId>4</IdentityId>
<FirstName>Roger</FirstName>
<LastName>Moore</LastName>
</Identity>
</Identities>
</Order>
</Orders>
XSLT 转换脚本。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes" />
<xsl:template match="/*">
<Orders>
<xsl:apply-templates select="Order[BookingHeader/Identities/Identity[LastName[text()]]]" />
</Orders>
</xsl:template>
<xsl:template match="Order">tra
<Order>
<OrderNo>
<xsl:value-of select="OrderNo" />
</OrderNo>
<Identities>
<xsl:for-each select="IdentityOrders/IdentityOrder">
<xsl:variable name="id" select="IdentityId" />
<xsl:for-each select="../../BookingHeader/Identities/Identity">
<xsl:if test="(IdentityId=$id) and (LastName!='') ">
<xsl:apply-templates select="." />
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</Identities>
</Order>
</xsl:template>
<xsl:template match="Identity">
<Identity>
<IdentityId>
<xsl:value-of select="IdentityId" />
</IdentityId>
<FirstName>
<xsl:value-of select="FirstName" />
</FirstName>
<LastName>
<xsl:value-of select="LastName" />
</LastName>
</Identity>
</xsl:template>
</xsl:stylesheet>
【问题讨论】:
您的示例非常令人困惑,因为 (a) 没有带有空 LastNama 的身份,并且 (b) 两个订单具有完全相同的身份,这使得很难看出哪个订单去了哪里。 【参考方案1】:我猜(!)你想做:
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="*"/>
<xsl:key name="id" match="Identity" use="concat(IdentityId, '|', ancestor::Order/OrderNo)" />
<xsl:template match="/Orders">
<xsl:copy>
<xsl:for-each select="Order">
<xsl:variable name="id" select="key('id', concat(IdentityOrders/IdentityOrder/IdentityId, '|', OrderNo))" />
<xsl:if test="$id/LastName/text()">
<xsl:copy>
<xsl:copy-of select="OrderNo"/>
<Identities>
<xsl:copy-of select="$id"/>
</Identities>
</xsl:copy>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这使用 key 来选择Identity
,其IdentityId
在IdentityOrders
中列出。然后它检查选定的Identity
在其LastName
中是否有值,如果有,它会复制Order
及其OrderNo
和选定的Identity
。
请注意,您的 XML 结构允许 Order
拥有多个 IdentityOrder
- 在这种情况下结果应该是什么尚不清楚。
【讨论】:
感谢您的回答。抱歉这个有点令人困惑的例子。是的,identityorders 中会有不止一个 identityorder。当我在 xml 中添加多个 identityorder 时,这种方法不起作用。你也有解决方案吗? 不,因为正如我所说,尚不清楚在这种情况下结果应该是什么。请编辑您的问题并阐明此处需要应用的逻辑。 所以我更新了我最初的例子。添加了更多订单和更多身份。 对不起,我不知道你想在这里完成什么。您是在举例说明,而不是在解释规则。我看到的唯一规则是“如果身份的姓氏为空,则订单不应包含在列表中” - 显然您的输出不遵循此规则,因为所有订单都包含在输出中。以上是关于Apply-Template 仅适用于 ID 基于父子节点列表的节点的主要内容,如果未能解决你的问题,请参考以下文章
jQuery TableSorter 仅适用于 ID(数字字段),不适用于文本、日期等其他字段
Facebook Messenger ID匹配API仅适用于管理员
来自 JBoss - RedHat codeready 的基于 Eclipse 的图形 Camel 编辑器是不是仅适用于 xml 中的骆驼?