【问题标题】:XSLT copy elements from xml by element matchXSLT 按元素匹配从 xml 复制元素
【发布时间】:2017-11-30 10:01:03
【问题描述】:

如果某些参数匹配,我需要将处理 xml 中的某些元素替换为其他 xml 中的元素。基本上,notifications.xml 是 xml,我需要在其中处理通知,并且只有在 notification-source.xml 中的 NotifId 等于当前通知的 NotifId 时才用来自 notification-source.xml 的 MsgText 替换/添加 MsgText。如果没有匹配,则保持通知不变。

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>

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。但目前我总是得到&lt;MsgText&gt;&lt;![CDATA[test]]&gt;&lt;/MsgText&gt; 所以我猜我没有正确使用测试(选择)

【问题讨论】:

  • 这个问题与stackoverflow.com/questions/44762709/… 不同吗?或者你为什么要问一个新问题?如果您希望我们了解您想要实现的目标,那么您应该向我们展示您发布的输入示例所需的结果,因为您的代码到目前为止还没有实现它。
  • 因为我无法删除旧问题,所以我要问一个新问题(我希望)有更好的描述。

标签: xml xslt transformation saxon


【解决方案1】:

&lt;xsl:variable name="currentNotifId" select="../NotifId/text()"/&gt; 的路径不对,应该是&lt;xsl:variable name="currentNotifId" select="../../NotifId/text()"/&gt;

您可能想学习使用键,然后简单地将条件放入匹配模式中:

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

在线http://xsltransform.net/93dEHFX

【讨论】:

  • 谢谢,我按照自己的方式使用它(使用固定路径)...当我在 Intellij IDE 中执行您的模板时,出现以下错误:[ERROR]: Could not compile stylesheet [FATAL]: Error checking type of the expression 'funcall(key, [literal-expr(note-ref), ParentLocationPath(ParentLocationPath(step("parent", -1), step("parent", -1)), step("child", 16)), parameter-ref(notifications-source/reference)])'.
  • 该错误消息非常表明您正在尝试将 XSLT 2.0 代码与 XSLT 1.0 处理器一起使用,尽管您告诉我们您使用的是 Saxon 9。
  • 我在 java 中使用 saxon 2...但我在 IDE 中测试了一些基本功能。感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多