【问题标题】:Extracting Nodes from multiple xml files从多个 xml 文件中提取节点
【发布时间】:2025-11-21 15:35:01
【问题描述】:

我有三个结构相似的 xml 文件,我想使用 xpath 表达式来提取这些文件中的所有匹配节点并将它们写入第三个文件。

你知道处理这个问题的好工具吗?

我正在考虑类似的事情

$supermagicxpathtool -x "//whoopdee" file1.xml file2.xml file3.xml > resultfile.xml

【问题讨论】:

  • 我认为也可以创建一个。至少在 C# 中没什么大不了的。顺便说一句,如果你能说出目的,可能还有一个更简单的替代方案。
  • 对不起! C# 不会帮助你。我不知道 bash 与 unix 平台有关

标签: xml bash xpath


【解决方案1】:

xmlstarlet可以提取节点,但我不确定它是否可以加入这样的结果。

【讨论】:

  • "亲爱的 XMLStarlet 用户,您可能已经注意到 xmlstarlet 的发展有些停滞了" 抱歉,这不是一个选项。
  • 看起来 xgrep 接近我正在寻找的内容
  • 它不是文字处理器,需要不断添加功能才能跟上潮流。它完成了它应该做的工作。这不是“停滞”,这是“维持模式”。
【解决方案2】:

XPath 只能选择节点,不能写入文件。

在 XPath 1.0 中,没有标准的方法来引用属于多个 XML 文档的单个表达式节点。如果托管 XPath 的编程语言是 XSLT,则三个 XML 文档的文档节点可以位于三个单独的 xsl:variables 中:$doc1$doc2$doc3

$doc1//whoopdee | $doc2//whoopdee | $doc3//whoopdee

或者,可以直接使用 XSLT document() 函数:

    document('file1.xml')//whoopdee 
  | document('file2.xml')//whoopdee 
  | document('file3.xml')//whoopdee

要输出上述任一 XPath 表达式的结果,使用 XSLT 只需编写:

<xsl:copy-of select="$doc1//whoopdee | $doc2//whoopdee | $doc3//whoopdee">

<xsl:copy-of select=
   "document('file1.xml')//whoopdee 
  | document('file2.xml')//whoopdee 
  | document('file3.xml')//whoopdee
">

在 XPath 2.0 中可以使用标准的doc() 函数,并且不会依赖于 XPath 的宿主。

命令行

可以使用任何允许命令行实例化的 XSLT 处理器。大多数 XSLT 处理器都允许这样做。它们还允许在命令行中传递简单的参数——通常格式为name=value。最后,大多数 XSLT 处理器允许将结果的目标文件指定为选项。这是 Saxon 文档的命令行用法链接:

http://www.saxonica.com/documentation/using-xsl/commandline.html

【讨论】:

    【解决方案3】:

    使用 xml-coreutils 包的 xml-cat 添加到 Unix 外观:

    xml-cat file1.xml file2.xml file3.xml | \
       xmlstarlet sel -R -t -c /root/whoopdee - | \
       xmlstarlet fo > resultfile.xml 
    

    【讨论】:

      【解决方案4】:

      xmlstarlet 可以将节点复制到另一个文档(因此这似乎是解决方案的第一步):

      # code example from:
      # "How to copy a node to another document",
      # http://sourceforge.net/projects/xmlstar/forums/forum/226076/topic/3558346
      
      xml sel -R -t -c / -c "document('f2.xml')" f1.xml | \
             xml ed -m /xml-select/Module_0 /xml-select/cnpsXML/Destinations/Module_0/Filter_1 | \
             xml sel -t -c /xml-select/* - | xml fo 
      
      # In pseudo code:
      # 1. Combine both documents into one (using -R to keep the combo a valid XML file - genius!)
      # 2. Move the element from f2.xml to its final destination
      

      要将所有匹配节点提取为纯(无标记)文本或 xsl,我们可以执行以下操作:

      xmlstarlet sel -t -m "//whoopdee" -v '@*' -v '.' -n file1.xml > resultfile
      
      xmlstarlet sel -C -t -m "//whoopdee" -v '@*' -v '.' -n file1.xml > resultfile.xsl
      xml tr resultfile.xsl file1.xml
      

      【讨论】:

        【解决方案5】:

        因此,在我之前的帖子 xmlstarlet 的基础上,似乎可以像这样完成工作:

        xmlstarlet sel -R -t -c / -c "document('file2.xml')" -c "document('file3.xml')" file1.xml | \
               xmlstarlet sel -R -t -c /xml-select/*/whoopdee - | xmlstarlet fo > resultfile.xml 
        
        xmlstarlet val resultfile.xml
        

        【讨论】:

          【解决方案6】:

          您似乎正在寻找工具 xpath,它位于 Ubuntu 中的包 libxml-xpath-perl 中,很可能是 Debian 和基于 - 的发行版。

          xpath [-s suffix] [-p prefix] [-q] -e query [-e query] ... [file] ...
          

          【讨论】: