3

I have two xml files A and B. I want to insert certain element nodes in A to B. It went fine but the imported elements were not "unescape" in B:

XML file A:

<?xml version="1.0"?>
<article>
  <publication>
     <authors>
      <author>
        <givenname locale="en_US">Admin</givenname>
        <givenname locale="nb_NO">Admin</givenname>
        <familyname locale="en_US">Septentrio</familyname>
        <email>[email protected]</email>
      </author>
      <author include_in_browse="true" user_group_ref="Forfatter" seq="0" id="13075">
        <givenname locale="nb_NO">Peter</givenname>
        <familyname locale="nb_NO">Nilsen</familyname>
        <affiliation locale="nb_NO">NTL University</affiliation>
        <country>NO</country>
        <email>[email protected]</email>
      </author>
    </authors>
  </publication>
</article>

XML file B:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.2 20190208//EN" "JATS-archivearticle1.dtd">
<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="other">
  <front>
  </front>
</article>

When I run:

xmlstarlet ed -L -s "//article/front" -t elem -n "newchild"  -v "$(xmlstarlet  sel  --omit-decl  -t -c "/article/publication/authors/author" a.xml)" b.xml

it gives me the following in B file:

<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.2 20190208//EN" "JATS-archivearticle1.dtd">
<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="other">
  <front>
  <newchild>&lt;author&gt;
        &lt;givenname locale="en_US"&gt;Admin&lt;/givenname&gt;
        &lt;givenname locale="nb_NO"&gt;Admin&lt;/givenname&gt;
        &lt;familyname locale="en_US"&gt;Septentrio&lt;/familyname&gt;
        &lt;email&gt;[email protected]&lt;/email&gt;
        &lt;/author&gt;&lt;author include_in_browse="true" user_group_ref="Forfatter" seq="0" id="13075"&gt;
        &lt;givenname locale="nb_NO"&gt;Peter&lt;/givenname&gt;
        &lt;familyname locale="nb_NO"&gt;Nilsen&lt;/familyname&gt;
        &lt;affiliation locale="nb_NO"&gt;NTL University&lt;/affiliation&gt;
        &lt;country&gt;NO&lt;/country&gt;
        &lt;email&gt;[email protected]&lt;/email&gt;
      &lt;/author&gt;</newchild></front>
</article>

How can I do unesc on the result.

Thanks.

Ofuuzo

0

3 Answers 3

2

Like this:

$ xmlstarlet unesc < file.xml
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.2 20190208//EN" "JATS-archivearticle1.dtd">
<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="other">
  <front>
  <newchild><author>
        <givenname locale="en_US">Admin</givenname>
        <givenname locale="nb_NO">Admin</givenname>
        <familyname locale="en_US">Septentrio</familyname>
        <email>[email protected]</email>
        </author><author include_in_browse="true" user_group_ref="Forfatter" seq="0" id="13075">
        <givenname locale="nb_NO">Peter</givenname>
        <familyname locale="nb_NO">Nilsen</familyname>
        <affiliation locale="nb_NO">NTL University</affiliation>
        <country>NO</country>
        <email>[email protected]</email>
      </author></newchild></front>
</article>

to edit in place:

$ xmlstarlet unesc < file.xml | sponge file
Sign up to request clarification or add additional context in comments.

3 Comments

Is there any other way to do unesc without piping the file?
@Ofuuzo: xmlstarlet unesc <file
@GillesQuénot: xmlstarlet unesc is not able to read a file by itself, it needs help from a shell. Because of this I used <file.
1

With xmllint, create newchild on file B and set its content to //author elements from file A

(printf '%s\n' "cd //article/front" "set <newchild></newchild>" "cd newchild" "set $(xmllint --xpath "//author" a.xml | sed -ze 's/\n/\&#xA;/g')" "save" "bye") | xmllint --shell b.xml

Output of one-liner

/ > cd //article/front
front > set <newchild></newchild>
front > cd newchild
newchild > set <author>&#xA;        <givenname locale="en_US">Admin</givenname>&#xA;        <givenname locale="nb_NO">Admin</givenname>&#xA;        <familyname locale="en_US">Septentrio</familyname>&#xA;        <email>[email protected]</email>&#xA;      </author>&#xA;<author include_in_browse="true" user_group_ref="Forfatter" seq="0" id="13075">&#xA;        <givenname locale="nb_NO">Peter</givenname>&#xA;        <familyname locale="nb_NO">Nilsen</familyname>&#xA;        <affiliation locale="nb_NO">NTL University</affiliation>&#xA;        <country>NO</country>&#xA;        <email>[email protected]</email>&#xA;      </author>&#xA;
newchild > save
newchild > bye

sed -ze 's/\n/\&#xA;/g' replaces plain new lines by their html entity to avoid sending them to piped xmllint --shell

Comments

0

Another approach would be to use xmlstarlet's XSLT processor to select the data from the other file and insert it, as a single operation, e.g. here's a simple XSLT stylesheet which uses the XPath expressions from your example, which I've called insert.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- the name of the document containing the author -->
    <xsl:param name="author-doc"/>
    <!-- copy the front element and insert authors at the end -->
    <xsl:template match="article/front">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
            <newchild>
                <xsl:copy-of select="document($author-doc)/article/publication/authors/author"/>
            </newchild>
        </xsl:copy>
    </xsl:template>
    <!-- copy the rest of the document unchanged -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

To invoke it:

xmlstarlet tr insert.xsl -s author-doc=a.xml b.xml

1 Comment

NB The XSLT above, while textually slightly longer than the other answers here, is arguably more readable and intelligible. It also doesn't tie you to xmlstarlet; you can execute the XSLT with xmlstarlet or you can use any other XSLT processor you like.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.