XSLT 通过元素匹配从 xml 复制元素
XSLT copy elements from xml by element match
如果某些参数匹配,我需要用来自其他 xml 的元素替换处理 xml 中的某些元素。基本上 notifications.xml 是 xml 其中我需要处理通知并且只有 replace/add MsgText with MsgText from notification-source.xml if in notification-source.xml NotifId equals NotifId of当前通知。如果没有匹配项,则保留通知不变。
notifications.xml
<?xml version="1.0" encoding="UTF-8"?>
<Notifications>
<BatchId>DOCATTR.BATCHID</BatchId>
<Notification>
<NotifId>1</NotifId>
<Cid>DOCATTR.CID</Cid>
<EmailNotification>
<CcAddress>DOCATTR.EMAILCC</CcAddress>
<CcName>DOCATTR.EMAILCCNAME</CcName>
<BccAddress>DOCATTR.EMAILBCC</BccAddress>
<SenderAddress>DOCATTR.SENDERADDRESS</SenderAddress>
<SenderName>DOCATTR.SENDERNAME</SenderName>
<MsgText>
</MsgText>
<Expiration>DOCATTR.EXPIRATION</Expiration>
<Priority>DOCATTR.PRIORITYNC</Priority>
</EmailNotification>
</Notification>
</Notifications>
通知-source.xml
<?xml version="1.0" encoding="UTF-8"?>
<Notifications>
<Notification>
<NotifId>1</NotifId>
<MsgText>
<![CDATA[notif 1]]>
</MsgText>
</Notification>
<Notification>
<NotifId>2</NotifId>
<MsgText>
<![CDATA[notif 2]]>
</MsgText>
</Notification>
</Notifications>
这是我正在尝试的,但它正在将 msgText 复制到其他地方
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" cdata-section-elements="MsgText"/>
<xsl:variable name="notifications" select="/"/>
<xsl:variable name="notifications-source" select="document('notifications-source.xml')"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<Notifications>
<xsl:for-each select="$notifications//Notification">
<xsl:variable name="currentNotifId" select="./NotifId"/>
<xsl:for-each select="$notifications-source//Notification">
<xsl:variable name="remoteNotifId" select="./NotifId"/>
<xsl:if test="$currentNotifId=$remoteNotifId">
<xsl:copy>
<xsl:copy-of select="./MsgText"/>
</xsl:copy>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</Notifications>
</xsl:template>
</xsl:stylesheet>
为此使用 saxon-he 9.6.0-6 会很好,但如果不适用,可以使用更新的版本。
所以我将模板更改为这个:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="MsgText">
<xsl:variable name="currentNotifId" select="../NotifId/text()"/>
<xsl:choose>
<xsl:when test="$notifications-source/Notifications/Notification/NotifId[text() = $currentNotifId]">
<xsl:copy>
<xsl:copy-of select="$notifications-source/Notifications/Notification/NotifId[text() = $currentNotifId]/../MsgText"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="'test'"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
现在我只匹配 MsgText。但目前我总是得到 <MsgText><![CDATA[test]]></MsgText>
所以我想我没有正确使用 test (choose)
路径<xsl:variable name="currentNotifId" select="../NotifId/text()"/>
不对,应该是<xsl:variable name="currentNotifId" select="../../NotifId/text()"/>
。
您可能想学习使用键来代替并简单地将条件放入匹配模式中:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:param name="notifications-source">
<Notifications>
<Notification>
<NotifId>1</NotifId>
<MsgText>
<![CDATA[notif 1]]>
</MsgText>
</Notification>
<Notification>
<NotifId>2</NotifId>
<MsgText>
<![CDATA[notif 2]]>
</MsgText>
</Notification>
</Notifications>
</xsl:param>
<xsl:key name="note-ref" match="Notification/MsgText" use="../NotifId"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="MsgText[key('note-ref', ../../NotifId, $notifications-source)]">
<xsl:copy-of select="key('note-ref', ../../NotifId, $notifications-source)"/>
</xsl:template>
</xsl:transform>
如果某些参数匹配,我需要用来自其他 xml 的元素替换处理 xml 中的某些元素。基本上 notifications.xml 是 xml 其中我需要处理通知并且只有 replace/add MsgText with MsgText from notification-source.xml if in notification-source.xml NotifId equals NotifId of当前通知。如果没有匹配项,则保留通知不变。
notifications.xml
<?xml version="1.0" encoding="UTF-8"?>
<Notifications>
<BatchId>DOCATTR.BATCHID</BatchId>
<Notification>
<NotifId>1</NotifId>
<Cid>DOCATTR.CID</Cid>
<EmailNotification>
<CcAddress>DOCATTR.EMAILCC</CcAddress>
<CcName>DOCATTR.EMAILCCNAME</CcName>
<BccAddress>DOCATTR.EMAILBCC</BccAddress>
<SenderAddress>DOCATTR.SENDERADDRESS</SenderAddress>
<SenderName>DOCATTR.SENDERNAME</SenderName>
<MsgText>
</MsgText>
<Expiration>DOCATTR.EXPIRATION</Expiration>
<Priority>DOCATTR.PRIORITYNC</Priority>
</EmailNotification>
</Notification>
</Notifications>
通知-source.xml
<?xml version="1.0" encoding="UTF-8"?>
<Notifications>
<Notification>
<NotifId>1</NotifId>
<MsgText>
<![CDATA[notif 1]]>
</MsgText>
</Notification>
<Notification>
<NotifId>2</NotifId>
<MsgText>
<![CDATA[notif 2]]>
</MsgText>
</Notification>
</Notifications>
这是我正在尝试的,但它正在将 msgText 复制到其他地方
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" cdata-section-elements="MsgText"/>
<xsl:variable name="notifications" select="/"/>
<xsl:variable name="notifications-source" select="document('notifications-source.xml')"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<Notifications>
<xsl:for-each select="$notifications//Notification">
<xsl:variable name="currentNotifId" select="./NotifId"/>
<xsl:for-each select="$notifications-source//Notification">
<xsl:variable name="remoteNotifId" select="./NotifId"/>
<xsl:if test="$currentNotifId=$remoteNotifId">
<xsl:copy>
<xsl:copy-of select="./MsgText"/>
</xsl:copy>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</Notifications>
</xsl:template>
</xsl:stylesheet>
为此使用 saxon-he 9.6.0-6 会很好,但如果不适用,可以使用更新的版本。
所以我将模板更改为这个:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="MsgText">
<xsl:variable name="currentNotifId" select="../NotifId/text()"/>
<xsl:choose>
<xsl:when test="$notifications-source/Notifications/Notification/NotifId[text() = $currentNotifId]">
<xsl:copy>
<xsl:copy-of select="$notifications-source/Notifications/Notification/NotifId[text() = $currentNotifId]/../MsgText"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="'test'"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
现在我只匹配 MsgText。但目前我总是得到 <MsgText><![CDATA[test]]></MsgText>
所以我想我没有正确使用 test (choose)
路径<xsl:variable name="currentNotifId" select="../NotifId/text()"/>
不对,应该是<xsl:variable name="currentNotifId" select="../../NotifId/text()"/>
。
您可能想学习使用键来代替并简单地将条件放入匹配模式中:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:param name="notifications-source">
<Notifications>
<Notification>
<NotifId>1</NotifId>
<MsgText>
<![CDATA[notif 1]]>
</MsgText>
</Notification>
<Notification>
<NotifId>2</NotifId>
<MsgText>
<![CDATA[notif 2]]>
</MsgText>
</Notification>
</Notifications>
</xsl:param>
<xsl:key name="note-ref" match="Notification/MsgText" use="../NotifId"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="MsgText[key('note-ref', ../../NotifId, $notifications-source)]">
<xsl:copy-of select="key('note-ref', ../../NotifId, $notifications-source)"/>
</xsl:template>
</xsl:transform>