【问题标题】:add an element to a node, if it doesnot exist, based on matching criteria如果元素不存在,则根据匹配条件将元素添加到节点
【发布时间】:2018-05-04 22:27:30
【问题描述】:

使用 XSLT 3.0,

我输入了以下 XML:

<?xml ="1.0" encoding="UTF-8"?>
    <TABLE NAME="TABLE.DB">
        <DATA RECORDS="2">
            <RECORD ID="1">
                <RECNO>1</RECNO>
                <SEQ>0</SEQ>
                <DATE>17/12/1999 2:44:08 μμ</DATE>
                <ID>12/11/2015 3:15:25 μμ</ID>
                <ORDER>10355</ORDER>
                <CN>PL</CN>
                <PROPERTY>06</PROPERTY>
            </RECORD>
            <RECORD ID="2">
                <RECNO>2</RECNO>
                <SEQUENCE>0</SEQUENCE>
                <DATE>17/12/1999 2:44:08 μμ</DATE>
                <ID>12/11/2015 3:15:25 μμ</ID>
                <ORDER>000026672</ORDER>
                <CN>PL 300 L</CN>
            </RECORD>
            <RECORD ID="3">
                <RECNO>3</RECNO>
                <SEQUENCE>0</SEQUENCE>
                <DATE>17/12/1999 2:44:08 μμ</DATE>
                <ID>12/11/2015 3:15:25 μμ</ID>
                <NUMBER>10357</NUMBER>
                <CN>PL 300 L</CN>
                <PROPERTY>0</PROPERTY>
            </RECORD>
        </DATA>
    </TABLE>

用于匹配的给定值: (我使用 \t 来定义我的输入文件的制表符分隔性质)

"10355"\t"PL"
"000026672"\t"PL 300 L"

我需要插入到所有没有PROPERTY标签的记录中,值为06

想要的结果:

 <?xml ="1.0" encoding="UTF-8"?>
    <TABLE NAME="TABLE.DB">
        <DATA RECORDS="2">
            <RECORD ID="1">
                <RECNO>1</RECNO>
                <SEQ>0</SEQ>
                <DATE>17/12/1999 2:44:08 μμ</DATE>
                <ID>12/11/2015 3:15:25 μμ</ID>
                <ORDER>10355</ORDER>
                <CN>PL</CN>
                <PROPERTY>06</PROPERTY>
            </RECORD>
            <RECORD ID="2">
                <RECNO>2</RECNO>
                <SEQUENCE>0</SEQUENCE>
                <DATE>17/12/1999 2:44:08 μμ</DATE>
                <ID>12/11/2015 3:15:25 μμ</ID>
                <ORDER>000026672</ORDER>
                <CN>PL 300 L</CN>
                <PROPERTY>06</PROPERTY>
            </RECORD>
            <RECORD ID="3">
                <RECNO>3</RECNO>
                <SEQUENCE>0</SEQUENCE>
                <DATE>17/12/1999 2:44:08 μμ</DATE>
                <ID>12/11/2015 3:15:25 μμ</ID>
                <NUMBER>10357</NUMBER>
                <CN>PL 300 L</CN>
            </RECORD>
        </DATA>
    </TABLE>

我尝试过添加元素属性,即使它已经存在,所以我最终会在同一个节点中得到两个元素属性,如果它已经存在的话。你能给我一个示例实现吗,我使用 SAXON 最新版本(9.8)

xsl: 添加一个元素,即使存在一个元素:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="xsl exsl xs">
    <xsl:output method="xml" version="1.0" indent="yes" encoding="utf-8" />
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="//*[local-name() = 'RECORD ID']">
        <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
            <xsl:choose>
                <xsl:when test="not(PRODUCT)">
                    <PRODUCT><xsl:value-of select="98"/></PRODUCT>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy><xsl:value-of select="98"/></xsl:copy>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

一直在使用我的真实数据建议的解决方案,(与示例有很大不同),我面临以下问题:

我怎么能有一份报告让我知道,根据输入文件,哪些添加是要完成的,但没有插入?

【问题讨论】:

  • 看起来与stackoverflow.com/questions/46419943/…stackoverflow.com/questions/46588096/… 非常相似,这两个问题的输入数据和答案都相似。你是在做一个有练习的课程吗?或者这种格式是从哪里来的?
  • 我也有这个类似的问题,看过上面的问题和答案,所以我想我会使用这些样本数据。我尝试做的是根据匹配标准在每个节点中添加一个标签,如果它不存在的话。所以一般的问题可能是:我应该如何输入数据以进行匹配?并且我应该使用哪个 xslt,以便向每个节点插入一个带有值的标签,该标签与条件匹配:匹配条件如下:插入一个标签,只有当 TAG A 和 TAG B 等于给定的值时。
  • 查看类似的问题和答案,如stackoverflow.com/questions/46345801/…,其中将制表符分隔的数据与输入中的节点进行比较。
  • 我使用了上述问题的解决方案,虽然我说要匹配 100 行,但只添加了 88 个标签。有没有办法记录替换日志,以便确切知道发生了什么?
  • 根据需要使用xsl:message输出节点、变量或调试表达式。

标签: xslt-3.0


【解决方案1】:

您的解决方案需要进行一些更改:

  1. 模板应该匹配RECORD,而不是RECORD IDID属性,不参与任何决定)。

  2. 您的总体概念还可以:

    • 复制起始标签(&lt;RECORD&gt;),
    • 应用模板到当前RECORD里面,
    • 检查PROPERTY(不是PRODUCT)元素是否不存在(在 当前RECORD),
    • 如果是(不存在),则输出具有所需值的PROPERTY元素,
    • 复制结束标签 (&lt;/RECORD&gt;)。
  3. 我删除了otherwise 部分(不需要)并将choose 更改为 一个if..

  4. 正如您指定的 XSLT 3.0,即使是 身份模板 也可以 替换为(短一点)on-no-match="shallow-copy"

  5. 我还在您的源 XML 中添加了 version。否则格式不正确。

所以整个脚本如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="RECORD">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
        <xsl:if test="not(PROPERTY)">
          <PROPERTY>06</PROPERTY>
        </xsl:if>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/上测试

【讨论】:

    【解决方案2】:

    一些观察:

    (a) 在您的示例输出中,PROPERTY 元素已从记录 3 中删除。我在您的需求描述中看不到任何解释原因的内容。

    (b) 在您的需求声明中,“我需要插入到所有还没有 PROPERTY 标记的记录中,值为 06”是不明确的。我的意思是,如果有一个属性“标签”(正确地,元素)的值不是 06,那么您应该插入另一个 PROPERTY 元素,但这似乎与您在其他地方所说的相矛盾。

    (c) 您的代码有一个带有match="//*[local-name() = 'RECORD ID']" 的模板规则。您可以删除匹配模式开头的“//”,这是多余的。更重要的是,没有元素的本地名称等于“RECORD ID”——元素名称不能包含空格。所以模板规则永远不会匹配任何东西。

    (d) 假设此模板规则旨在匹配 RECORD 元素,您当然不希望 xsl:copy 包含在 xsl:otherwise 中,因为这将创建整个 RECORD 的嵌套副本。

    (e) 您要求 XSLT 3.0 解决方案,但您的问题中没有任何需要 XSLT 3.0 的内容,实际上您自己的样式表显示 version="2.0"。

    (f) 我看不出制表符分隔的参数文件在其中扮演什么角色。

    简而言之,在任何人开始编写任何代码之前,都需要进行大量的澄清。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-07
      • 2020-10-25
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 2016-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多