xml 批量文件编辑器按数字递增

xml bulk file editor increment by numbers

我试图在我的所有 xml 文件中以递增方式为 TEXT_VALUE 字段的值添加前缀,只有名为 "TRANSL" 和 ID= 的标签"Example"。 目前我是手动做的,但是因为我有几千个,我想我应该通过编程来做。

这是初始版本:

<TRANSL ID="Example">
    <TRANSCIPT>
        <REF_TEXT TEXT_ID="a680" TXT_TM="a24">
            <TEXT_VALUE>this is an example</TEXT_VALUE>
        </REF_TEXT>
    </TRANSCIPT>
    <TRANSCIPT>
        <REF_TEXT TEXT_ID="a681" TXT_TM="a25">
            <TEXT_VALUE>another example</TEXT_VALUE>
        </REF_TEXT>
    </TRANSCIPT>
    <TRANSCIPT>
        <REF_TEXT TEXT_ID="a682" TXT_TM="a26">
            <TEXT_VALUE>third example</TEXT_VALUE>
        </REF_TEXT>
    </TRANSCIPT>
</TRANS>

这是编辑后的版本:

<TRANSL ID="Example">
    <TRANSCIPT>
        <REF_TEXT TEXT_ID="a680" TXT_TM="a24">
            <TEXT_VALUE>1-this is an example</TEXT_VALUE>
        </REF_TEXT>
    </TRANSCIPT>
    <TRANSCIPT>
        <REF_TEXT TEXT_ID="a681" TXT_TM="a25">
            <TEXT_VALUE>2-another example</TEXT_VALUE>
        </REF_TEXT>
    </TRANSCIPT>
    <TRANSCIPT>
        <REF_TEXT TEXT_ID="a682" TXT_TM="a26">
            <TEXT_VALUE>3-third example</TEXT_VALUE>
        </REF_TEXT>
    </TRANSCIPT>
</TRANS>

如何以编程方式进行?那里有专业的 xml 编辑吗?如果没有,我如何在 python 或 powershell、perl、记事本 ++ 或任何其他程序中执行此操作?

这是我在 python 中作为记事本 ++ 插件的脚本:

def increment_replace(match):
    return "<TEXT_VALUE>{}".format(str(int(match.group(1))+1))

editor.rereplace(r'\<TEXT_VALUE\>', increment_replace)

但它不起作用...

要获取 <TEXT_VALUE> 元素的当前计数/position(),您可以参考父 <TRANSCIPT> 元素的计数/position()

为了将此计数传递给后续模板 I used the solution from this SO answer 并将其方法合并到 身份模板 中,现在传递包含一些值的 num 参数。 num 参数在所有 <TRANSCIPT> 元素之上的 <for-each> 循环中生成,并向下传递到 <apply-templates> 层次结构以用于 TEXT_VALUE 模板(在其他任何地方都是只是被忽略了)。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <!-- modified identity template -->
  <xsl:template match="node()|@*">
    <xsl:param name="num" />
    <xsl:copy>  
      <xsl:apply-templates select="node()|@*">
        <xsl:with-param name="num" select="$num"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="TRANSL">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:for-each select="TRANSCIPT">
        <xsl:copy>
        <xsl:apply-templates>
          <xsl:with-param name="num" select="position()" />
        </xsl:apply-templates>
        </xsl:copy>
      </xsl:for-each>    
    </xsl:copy>
  </xsl:template>

  <xsl:template match="TEXT_VALUE[../../../@ID='Example']">   <!-- added after extension of question -->
    <xsl:param name="num" />
    <xsl:element name="TEXT_VALUE">
      <xsl:value-of select="concat($num,'-',text())" />
    </xsl:element>        
  </xsl:template>

</xsl:stylesheet>

编辑:
在评论中扩展要求后,我向 TEXT_VALUE 模板添加了一个谓词,将匹配规则修改为仅 select TEXT_VALUE 具有 @ID 属性且值为"Example".

要使用 count(preceding-sibling::*) 使用变体 XSLT 脚本添加到 @zx485,请考虑使用 lxml 的以下 Python 解决方案。作为信息,XSLT 是一种用于转换 XML 文件的专用语言,可以成为将初始 XML 文件处理为最终使用格式的便捷工具。

由于 Python 是一种通用语言,您可以利用它的 os 文件系统模块和第三方模块 lxml(一个完全兼容的 W3C 库,具有 XPath 1.0 和XSLT 1.0 功能)以迭代方式创建所需的输出。

XSLT (另存为 .xsl 文件以在 Python 中解析)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>

  <!-- Identity Transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Add Incremenet Number to Text -->
  <xsl:template match="TEXT_VALUE[ancestor::TRANSL/@ID='Example']">
    <xsl:copy>      
      <xsl:value-of select="concat(count(ancestor::TRANSCIPT/preceding-sibling::TRANSCIPT)+1, '-', text())"/>
    </xsl:copy>
  </xsl:template>

</xsl:transform>

Python

import os
import lxml.etree as et

# CHANGE DIRECTORY
os.chdir('/path/to/raw/XML/files')

# LOAD XSLT SCRIPT AND INITIALIZE TRANSFORMER
xslt = et.parse('/path/to/XSLT_Script.xsl')
transform = et.XSLT(xslt)

for file in os.listdir():
   if file.endswith('.xml'):

      # LOAD SOURCE XML
      dom = et.parse(file)

      # TRANSFORM TO NEW TREE
      newdom = transform(dom)

      # SAVE TO FILE (SAME NAME WITH _new SUFFIX)
      with open(file.replace('.xml', '_new.xml'), 'wb') as f:
          f.write(newdom)