Marco Randazzo
Marco Randazzo

Reputation: 19

How can I save an xml containing multiple xml:base attributes to multiple files

I have an xml file similar to:

<main xmlns:xi="http://www.w3.org/2001/XInclude">
  <level1 xml:base="./include1/include1.xml">
    <level2 xml:base="./include1/include2/include2.xml">
      <level3 xml:base="./include2/include3/include3.xml">
        <level4 xml:base="./include3/include4/include4.xml">
          <data>0</data>
          <data>1</data>
        </level4>
      </level3>
    </level2>
  </level1>
</main> 

The file was generated by assembling multiple xml files through the use of xi:include. In particular, the file in the example is generated by the following files:

./main.xml

<?xml version="1.0" encoding="UTF-8" ?>
<main  xmlns:xi="http://www.w3.org/2001/XInclude">
    <xi:include href="./include1/include1.xml" />
</main >

./include1/include1.xml

<?xml version="1.0" encoding="UTF-8" ?>
<level1  xmlns:xi="http://www.w3.org/2001/XInclude">
    <xi:include href="./include2/include2.xml" />
</level1 > 

./include1/include2/include2.xml

<?xml version="1.0" encoding="UTF-8" ?>
<level2  xmlns:xi="http://www.w3.org/2001/XInclude">
    <xi:include href="./include3/include3.xml" />
</level2 > 

./include1/include2/include3/include3.xml

<?xml version="1.0" encoding="UTF-8" ?>
<level3  xmlns:xi="http://www.w3.org/2001/XInclude">
    <xi:include href="./include4/include4.xml" />
</level3 > 

./include1/include2/include3/include4/include4.xml

<?xml version="1.0" encoding="UTF-8" ?>
<level4  xmlns:xi="http://www.w3.org/2001/XInclude">
    <data> 0 </data>
    <data> 1 </data>
</level4 > 

Now, after doing some processing on the data in the output file, I would like to save back the original files, retrieving the original folder tree structure.

I tried to write my own XQuery script to accomplish this goal, by recurring inside the output file, processing the values stored in the xml:base attributes and saving the files.

However, now, after writing more than 150 lines of beginner-level XQuery code, I feel lost.

I'm thus wondering if someone has already developed some XQuery or XSLT code that implements this functionality (I think that overall it should be a pretty common functionality...) or if I can use some existing library to perform this task. Thank you

Upvotes: 0

Views: 82

Answers (1)

Michael Kay
Michael Kay

Reputation: 163575

I think you could do it fairly easily in XSLT with something like

<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:mode on-no-match="shallow-copy">
  <xsl:template match="*[@xml:base]">
    <xi:include href="{@xml:base}"/>
    <xsl:result-document href="{@xml:base}">
      <xsl:copy>
        <xsl:copy-of select="@* except @xml:base"/>
        <xsl:apply-templates/>
      </xsl:copy>
    </xsl:result-document>
  </xsl:template>
</xsl:transform> 

I don't see how you could do it in XQuery which lacks any equivalent of xsl:result-document.

The only difficulty is getting the value of the href attribute correct on both the xsl:result-document and the xi:include elements. The way I've written it, the relative URI in the @xml:base attribute will be resolved against the base output URI of the transformation. You might get better results using the value of base-uri(.) which resolves it against ancestor base URIs, but the problem is that is then likely to be an absolute URI in the same directory as the source document. Perhaps use base-uri(.) with some prefix-stripping to make it relative, or perhaps use an OutputURIResolver to redirect the final output location.

Upvotes: 1

Related Questions