【问题标题】:update XML string using sed使用 sed 更新 XML 字符串
【发布时间】:2018-12-25 22:44:17
【问题描述】:

我有一个类似如下的 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<csw:GetRecordByIdResponse xmlns:csw="http://www.opengis.net/cat/csw/2.0.2">
  <xmlns:gmi="http://sdi.eurac.edu/metadata/iso19139-2/schema/gmi" xmlns:gmd="http://www.isotc211.org/2005/gmd" xmlns:gco="http://www.isotc211.org/2005/gco" xmlns:gml="http://www.opengis.net/gml" xmlns:geonet="http://www.fao.org/geonetwork" gco:isoType="gmd:MD_Metadata">
    <gmd:onLine>
                  <gmd:CI_OnlineResource>
                    <gmd:linkage>
                      <gmd:URL>http://server.test.it/geoserver/test_product/wms?SERVICE=WMS&amp;TIME=2018-06-14T10:59:00Z&amp;</gmd:URL>
                    </gmd:linkage>
                    <gmd:protocol>
                      <gco:CharacterString>OGC:WMS-1.1.1-http-get-map</gco:CharacterString>
                    </gmd:protocol>
                    <gmd:name>
                      <gco:CharacterString>test_product:test_product</gco:CharacterString>
                    </gmd:name>
                    <gmd:description>
                      <gco:CharacterString>test_product:test_product</gco:CharacterString>
                    </gmd:description>
                  </gmd:CI_OnlineResource>
    </gmd:onLine>
</csw>

我想将 标记的内容替换为以下内容:

http://server.test.it/geoserver/test_product/wms?SERVICE=WMS&version=1.1.0&request=GetMap&layers=test_product:test_product&styles=&bbox=140442.2309,3739661.3694,1330442.2309,2564661.3694&width=768&height=576&srs=EPSG:32632&format=application/openlayers&TIME=2018-06-14T10:59:00Z&amp;

我曾经在bash中使用sed命令:

correct_url='http://server.test.it/geoserver/test_product/wms?SERVICE=WMS&amp;version=1.1.0&amp;request=GetMap&amp;layers=test_product:test_product&amp;styles=&amp;bbox=140442.2309,3739661.3694,1330442.2309,2564661.3694&amp;width=768&amp;height=576&amp;srs=EPSG:32632&amp;format=application/openlayers&amp;TIME=2018-06-14T10:59:00Z&amp;'
sed -i 's/<gmd:URL>\(.*\)<\/gmd:URL>/<gmd:URL>'"${correct_url}"'<\/gmd:URL>/' xml_file.xml

它给了我一个错误:

sed: -e expression #1, char 52: `s' 的未知选项

你能告诉我我做错了什么吗?

更新:

使用@rubystallion 的建议,我尝试转义所有特殊字符:

correct_url='http://server.test.it/geoserver/test_product/wms?SERVICE=WMS&amp;version=1.1.0&amp;request=GetMap&amp;layers=test_product:test_product&amp;styles=&amp;bbox=140442.2309,3739661.3694,1330442.2309,2564661.3694&amp;width=768&amp;height=576&amp;srs=EPSG:32632&amp;format=application/openlayers&amp;TIME=2018-06-14T10:59:00Z&amp;'
correct_url_escaped="${correct_url//\//\\\/}"
correct_url_escaped="${correct_url_escaped//&/\\&}"
correct_url_escaped="${correct_url_escaped/\?/\?}"
correct_url_escaped="${correct_url_escaped/\?/\?}"
correct_url_escaped="${correct_url_escaped//\;/\;}"
correct_url_escaped="${correct_url_escaped//\=/\=}"

sed -i 's/<gmd:URL>\(.*\)<\/gmd:URL>/<gmd:URL>'"${correct_url_escaped}"'<\/gmd:URL>/' xml_file.xml

但我仍然收到错误:

sed: -e expression #1, char 47: `s' 的未知选项

我还是错过了什么吗?

【问题讨论】:

  • 不要使用sed修改XML;相反,请使用可识别 XML 的工具。
  • 您的 XML 无效:xmllint 返回许多 namespace error : Namespace prefix gmd on ... is not defined
  • @choroba 我添加了命名空间。我忘记写了
  • Don't Parse XML/HTML With Regex. 我建议使用 XML/HTML 解析器 (xmlstarlet, xmllint ...)。
  • @Cyrus 类似于 xmlstarlet ed -u "//gmd:url" -v $correct_url xml_file.xml ?

标签: xml bash sed


【解决方案1】:

正如评论者所提到的,您可以编写更多可维护的脚本并通过使用 XML 感知工具避免出错,但让我向您展示为什么您的代码不起作用:

Bash 在执行命令之前将字符串中的变量替换为其内容,因此/ 将被 sed 解析为分隔符,&amp; 将被解析为替换字符串中的整个匹配项。如果您正确转义特殊字符,那么您的命令将按预期工作:

correct_url='http://server.test.it/geoserver/test_product/wms?SERVICE=WMS&amp;version=1.1.0&amp;request=GetMap&amp;layers=test_product:test_product&amp;styles=&amp;bbox=140442.2309,3739661.3694,1330442.2309,2564661.3694&amp;width=768&amp;height=576&amp;srs=EPSG:32632&amp;format=application/openlayers&amp;TIME=2018-06-14T10:59:00Z&amp;'
correct_url_escaped="${correct_url//\//\\\/}"
correct_url_escaped="${correct_url_escaped//&/\\&}"

token='http://server.test.it/geoserver/test_product/wms?SERVICE=WMS&amp;TIME=2018-06-14T10:59:00Z&amp;'

sed -i 's/<gmd:URL>\(.*\)<\/gmd:URL>/<gmd:URL>'"${correct_url_escaped}"'<\/gmd:URL>/' xml_file.xml

另外,请确保您的命令下次按照问题中的描述进行编译。您忘记在变量周围加上引号。

【讨论】:

  • 嗨@rubystallion 不幸的是我不得不说我仍然遇到同样的错误sed: -e expression #1, char 47: unknown option to `s' PS 我添加引号。谢谢!
  • 您不必转义问号,因为您将 URL 插入替换的替换部分,其中问号没有特殊含义。如果您将我提供的代码逐字复制到与 XML 文件位于同一目录中的文件 script.sh 中,然后运行 ​​bash script.sh,它应该可以工作。要转义特殊字符,您必须使用反斜杠,这就是我在第二行和第三行中使用 bash 替换所做的。
【解决方案2】:

您的 URL 中包含特殊字符,并且您正在将 URL 替换为执行的命令。如果你在你的sed 命令行前面放置一个echo,你会看到实际执行了什么,这显然不是一个有效的sed 命令。

您需要转义 URL,或者只是将其直接放入您的 sed 命令中。您可以通过使用e 标志来实现后者,它将匹配的文本替换为执行命令的结果。像这样:

url="http://x:y@www.a.com/foo?a=b&c=d" sed -r -i 's/(\s*)<gmd:URL>(.*)<\/gmd:URL>/echo "\1<gmd:URL>$url<\/gmd:URL>"/e' xml_file.xml

注意,您应该谨慎使用e 标志;因为您正在执行某些事情,所以存在潜在的安全问题。

另外,请注意有关使用 XML 编辑工具编辑 XML 的一般好建议(在这样的简单工作中,IMO 可以使用sed,如果它是完成它的最快方法...)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 2019-09-16
    • 2012-12-02
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多