0

In a directory with several XML files (there may be hundreds of files) I have a field called <import_url>. In this field it can happen that a URL has an underscore.

I would like this underscore to be replaced by a hyphen, such as in the example below:

in_natur

<import_url>archiv/in_natur/der-beitrag-name.html</import_url>

Should be

<import_url>archiv/in-natur/der-beitrag-name.html</import_url>

How can I search and replace this in linux command line?

For reference, here's the entire XML file

<article id="6577889" type="article">
  <author>
    <forename>Hans</forename>
    <surname>Wurs</surname>
    <email>[email protected]</email>
    <title></title>
    <position></position>
    <authorId>23262452</authorId>
  </author>
  <headline>Der Titel des Beitrags</headline>
  <body>
    Fringilla placerat elementum ratione? Illum blandit wisi adipisicing at sunt, proin minim. Quibusdam similique soluta, viverra 
    excepteur sem justo commodo? Congue eiusmod, temporibus doloribus urna pulvinar. Quibusdam elementum ante pretium nostra atque, 
  </body>
  <date>
    <createdDate>2020-04-30T10:44:35+00:00</createdDate>
    <publishingDate>2020-04-30T00:00:00+00:00</publishingDate>
  </date>
  <metaDescription>Faucibus quidem quo, nostrud voluptates nunc mollitia curae</metaDescription>
  <import_url>archiv/in_natur/der-beitrag-name.html</import_url>
  <taxonomy type="channel">
    <channel id="Archiv:Natur" parent="Archiv">Natur</channel>
 </taxonomy>
</article>
1
  • I'm sure someone will come up with a good sed regex expression, but the key here is to a) figure out how to edit the files then b) run this against all files in the directory.
    – Pedro
    May 22, 2020 at 10:36

2 Answers 2

2

If you have a properly formed XML document you can use an XML parser/editor to modify it

Source file, /tmp/xml

<article>
  <-- other sections omitted -->
  <import_url>archiv/in_natur/der-beitrag-name.html</import_url>
</article>

Modification

xmlstarlet edit --update '/article/import_url' --expr 'translate(., "_", "-")' /tmp/xml

Output

<?xml version="1.0"?>
<article>
  <-- other sections omitted -->
  <import_url>archiv/in-natur/der-beitrag-name.html</import_url>
</article>

Since the matching uses XPath you can match on //import_url if you prefer.

You can also add --inplace if you really want to edit your files in-place. I don't generally recommend that though; it's better to write to a temporary file and if that's successful then (and only then) replace the source.

1

Similarly to the xmlstarlet solution, here's how you do it using Saxon's Gizmo utility:

java net.sf.saxon.Gizmo -s:/tmp/xml
/>update //import_url translate(., '_', '-')
/>save /tmp/xml
/>quit

https://saxonica.com/documentation/index.html#!gizmo

To process all the files in a directory, you can run this XSLT 3.0 transformation:

<xsl:transform version="3.0" expand-text="yes" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="import_url">
  <xsl:copy>{translate(., '_', '-')}</xsl:copy>
</xsl:template>

<xsl:template name="xsl:initial-template">
  <xsl:for-each select="collection('file:///my/input/directory?recurse=yes')">
    <xsl:result-document href="file:///my/output/directory/{tokenize(document-uri(),'/')[last()]}">
      <xsl:apply-templates/>
    </xsl:result-document>
  </xsl:for-each>
</xsl:template>

</xsl:transform>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .