【问题标题】:How to replace specific xml node value using sed or awk如何使用 sed 或 awk 替换特定的 xml 节点值
【发布时间】:2021-01-30 23:01:26
【问题描述】:

我想使用sedawk 替换特定的xml 节点值。我不能使用专门的包来解析 xml,例如 xmlstarletxmllint 等。我必须使用 sedawk strong>,只是“基本”外壳。

我有很多大的 xml 文件。在该文件中,我想定位并替换两个标签值:示例:

<desc:partNumber>>2</desc:partNumber>
<desc:dateIssued>>1870</desc:dateIssued>

问题是,这些名称有数百个标签。但这两个标签的父标签在整个 xml 文件中是唯一的:

<desc:desc ID="DESC_VOLUME_0001">

另一个问题是每个文件中父 &lt;desc:desc ID="DESC_VOLUME_0001"&gt; 内的标签 &lt;desc:partNumber&gt;&lt;desc:dateIssued&gt; 的位置或行号是不同的。

我认为解决方案是:

  1. 定位并提取父级 &lt;desc:desc ID="DESC_VOLUME_0001"&gt; 及其子级到变量
  2. 迭代子节点并获取&lt;desc:partNumber&gt; 的位置(行号) 和&lt;desc:dateIssued&gt; 并保存到变量
  3. 将行号传递给sed 命令并替换当前值 具有新值的标签(将从 .csv 文件中读取新值)

我尝试创建这个sed 命令,你可以看到我使用'n' 来移动行,但这需要是可变的。

sed -i '/desc:desc ID="DESC_VOLUME_0001"/{n;n;n;n;n;n;n;n;n;s/'"${OLD_DATE_ISSUED}"'/'"${NEW_DATE_ISSUED}"'/}'

有子节点的父节点:

<desc:desc ID="DESC_VOLUME_0001"> 
    <desc:physicalDescription> 
        <desc:note>text</desc:note> 
    </desc:physicalDescription>  
    <desc:titleInfo> 
        <desc:partNumber>2</desc:partNumber> 
    </desc:titleInfo>  
    <desc:originInfo> 
        <desc:dateIssued>1870</desc:dateIssued> 
    </desc:originInfo>  
    <desc:identifier type="uuid">81e32d30-6388-11e6-8336-005056827e52</desc:identifier> 
</desc:desc> 

任何人都可以帮助如何实现这一目标?

【问题讨论】:

  • 请在您的问题中添加示例输入(无描述、无图像、无链接)以及该示例输入所需的输出(无评论)。
  • 不能使用专门的包来解析 xml,如 xmlstarlet、xmllint 等。 你应该告诉做出这个决定的人,他们在给你下跪。使用 XML 感知工具是稳健有效地执行此操作的唯一方法。
  • 为什么不使用单独的 sed 替换打开和关闭标签?并且请注意尖括号,以免您也意外替换 desc:partNumberClient。
  • "我必须使用 sed 或 awk,只是“基本”外壳。"不,你没有。这是工作的错误工具。您的代码将不正确且效率低下。
  • 相关:bobinceRegEx match open tags except XHTML self-contained tags 的警示性回答

标签: xml bash awk sed xml-parsing


【解决方案1】:

使用xmldata文件中的示例数据:

awk -v dID="DESC_VOLUME_0001" -v part="5" -v dissue=1850 -F[\<\>] 
  '$2 ~ /desc ID/ { 
                     split($2,arr,"\"");
                     descID=arr[2] 
                  } 
   $2 ~ /desc:partNumber/ { 
                            if (descID==dID) { 
                                               $0=gensub($3,part,$0) 
                                             } 
                          } 
   $2 ~ /desc:dateIssued/ { 
                            if (descID==dID) 
                                             { 
                                               $0=gensub($3,dissue,$0) 
                                             } 
                          }
   1' xmldata

一个班轮:

 awk -v dID="DESC_VOLUME_0001" -v part="5" -v dissue=1850 -F[\<\>] '$2 ~ /desc ID/ { split($2,arr,"\"");descID=arr[2] } $2 ~ /desc:partNumber/ { if (descID==dID) { $0=gensub($3,part,$0) } } $2 ~ /desc:dateIssued/ { if (descID==dID) { $0=gensub($3,dissue,$0) } }1' xmldata

这里我们将分隔符设置为 我们还将 dID 设置为我们要搜索的 desc ID,part 部分是我们要更改为的 partNumber,dissue 是我们要更改的 dateIssued。

然后我们在行中搜索 desc ID 文本,并根据双引号将行拆分以获得数组 arr 的第二个索引,然后使用该索引创建变量 descID。

我们进一步搜索 partNumber 和 dateIssued,检查是否 dID=descID。如果它们匹配,我们使用 gensub 函数将 $0 行中的第三个分隔字段替换为传递的变量,并将 $0 设置为结果。我们最终打印到 1 的行(更改或其他)。

【讨论】:

  • 效果很好。谢谢
猜你喜欢
  • 2020-01-17
  • 2013-12-30
  • 2016-12-23
  • 1970-01-01
  • 2014-02-05
  • 2019-05-12
  • 2021-03-22
  • 1970-01-01
  • 2017-09-06
相关资源
最近更新 更多