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)
我试图在我的所有 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)