匹配属性值后添加新的兄弟节点

Posted

技术标签:

【中文标题】匹配属性值后添加新的兄弟节点【英文标题】:Add a new sibling node after matching attribute value 【发布时间】:2022-01-09 07:43:02 【问题描述】:

我需要在模板匹配后添加一个节点。 模板匹配基于参数的属性值。 我已经成功地将节点添加为匹配属性的子节点。但是,我需要添加的节点是兄弟节点,而不是子节点。 有没有办法将注释添加为同级,而不是作为匹配属性的子级?

这是我的 xml 文件:

 <WORK SRCDBID="DBIDxx" DSTDBID="SERVER" WORKTYPE="DELTA" SETNUMBER="1">
 <TXID SRCDBID="DBIDxx" CPDATE="2021200932651" TYPE="0">
 <OP ACTION="I" TBL="RTD-WORKORDER">
 <COLS>
 <COL NAME="WoNum" VAL="303105525"/>
 <COL NAME="NumWoLin" VAL="1"/>
 <COL NAME="LinNum" VAL="1"/>
 <COL NAME="RtrdTag" VAL="527395802"/>
 </COLS>
 </OP>
 </TXID>
 </WORK>

我的失败结果:

<WORK SRCDBID="DBIDxx" DSTDBID="SERVER" WORKTYPE="DELTA" SETNUMBER="1">
<TXID SRCDBID="DBIDxx" CPDATE="2021200932651" TYPE="0">
<OP ACTION="I" TBL="RTD-WORKORDER">
<COLS>
<COL NAME="WoNum" VAL="303105525"/>
<COL NAME="NumWoLin" VAL="1"/>
<COL NAME="LinNum" VAL="1"/>
<COL NAME="RtrdTag" VAL="527395802">
    <COL NAME="DuplicateTag" VAL="0303105525|31"/>
</COL>
</COLS>
</OP>
</TXID>
</WORK>

我想要的结果:

<WORK SRCDBID="DBIDxx" DSTDBID="SERVER" WORKTYPE="DELTA" SETNUMBER="1">
<TXID SRCDBID="DBIDxx" CPDATE="2021200932651" TYPE="0">
<OP ACTION="I" TBL="RTD-WORKORDER">
<COLS>
<COL NAME="WoNum" VAL="303105525"/>
<COL NAME="NumWoLin" VAL="1"/>
<COL NAME="LinNum" VAL="1"/>
<COL NAME="RtrdTag" VAL="527395802"/>
<COL NAME="DuplicateTag" VAL="031123123|31"/>
</COLS>
</OP>
</TXID>
</WORK>

我的 xsl: 参数值为: rtdTag = "527395802" rtdDupTag = "0303105525|31"

<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" media-type="text/xml" method="xml" />

  <xsl:param name="rtdTag" />
  <xsl:param name="rtdDupTag" />

  <!-- This is the default template that copied everything -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- This is the "override" template for specific elements that match the passed in tag. -->
  <xsl:template match="@*[. = $rtdTag]">
    <!-- Copy the element everything inside it -->
    <xsl:copy>
      <xsl:copy-of select="node()"/>
    </xsl:copy>

    <!-- Add new node  -->
      <xsl:element name="COL">
        <xsl:attribute name="NAME">
          <xsl:text>DuplicateTag</xsl:text>
        </xsl:attribute>
        <xsl:attribute name="VAL">
          <xsl:value-of select="$rtdDupTag"/>
        </xsl:attribute>
        <xsl:apply-templates/>
      </xsl:element>
  </xsl:template>
</xsl:stylesheet>

【问题讨论】:

【参考方案1】:

更改您的模板以匹配具有该属性的元素,然后在复制该元素后添加新元素。

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" media-type="text/xml" method="xml" />
    
    <xsl:param name="rtdTag" />
    <xsl:param name="rtdDupTag" />
    
    <!-- This is the default template that copied everything -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- This is the "override" template for specific elements that match the passed in tag. -->
    <xsl:template match="*[@* = $rtdTag]">
        <!-- Copy the element everything inside it -->
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
        
        <!-- Add new node  -->
        <xsl:element name="COL">
            <xsl:attribute name="NAME">
                <xsl:text>DuplicateTag</xsl:text>
            </xsl:attribute>
            <xsl:attribute name="VAL">
                <xsl:value-of select="$rtdDupTag"/>
            </xsl:attribute>
            
        </xsl:element>

    </xsl:template>
</xsl:stylesheet>

如果你静态知道元素和属性的名称,我更喜欢元素和属性的字面量,而不是使用xsl:elementxsl:attribute

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" media-type="text/xml" method="xml" />
    
    <xsl:param name="rtdTag" />
    <xsl:param name="rtdDupTag" />
    
    <!-- This is the default template that copied everything -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- This is the "override" template for specific elements that match the passed in tag. -->
    <xsl:template match="*[@* = $rtdTag]">
        <!-- Copy the element everything inside it -->
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
        
        <!-- Add new node  -->
        <COL NAME="DuplicateTag" VAL="$rtdDupTag"/>
    </xsl:template>
    
</xsl:stylesheet>

【讨论】:

以上是关于匹配属性值后添加新的兄弟节点的主要内容,如果未能解决你的问题,请参考以下文章

访问兄弟节点

访问兄弟节点

XSLT 将具有父节点的节点移动到具有给定属性的每个父节点的兄弟节点中

Python爬虫编程思想(54):使用Beautiful Soup选择兄弟节点

如何使用xsl根据属性将xml的兄弟节点更改为父节点和子节点

parentNode,children,nextSibling,previousSibling常用属性对比