0

I’m trying since this morning to add value in a xml file using xslt. So basically i have this xml file 1.xml

<?xml version="1.0" encoding="UTF-8"?>
<Orderfile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  <order>
    <establishmenthour>10:38:00</ establishmenthour>
    <ExpirationDate/>
    <acc/>
    <identification>170610009-01</identification>
  </order>
  <order>
    <establishmenthour>10:40:00</ establishmenthour>
    <ExpirationDate/>
    <acc/>
    <identification>170610910-03</identification>
  </order>
  <order>
    <establishmenthour>10:42:00</ establishmenthour>
    <ExpirationDate/>
    <acc/>
    <identification>170610015-01</identification>
  </order>

And I have these informations from a second xml file called 2.xml

<?xml version="1.0" encoding="UTF-8" ?> 
<Orderfile>
<order>
  <identification>170610009-01</identification> 
  <ExpirationDate>2017-06-21</ExpirationDate> 
  </order>
<order>
  <identification>170610015-01</identification> 
  <ExpirationDate>2017-02-22</ExpirationDate> 
  </order>
<order>
  <identification>170610024-01</identification> 
  <ExpirationDate>2017-08-02</ExpirationDate> 
  </order>
  </Orderfile>

And I would like to have that --> merged.xml

<?xml version="1.0" encoding="UTF-8"?>
<Orderfile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  <order>
    <establishmenthour>10:38:00</establishmenthour>
    <ExpirationDate>2017-06-21</ExpirationDate/>
    <acc/>
    <identification>170610009-01</identification>
  </order>
  <order>
    <establishmenthour>10:40:00</ establishmenthour>
    <ExpirationDate/>
    <acc/>
    <identification>170610910-03</identification>
  </order>
  <order>
    <establishmenthour>10:42:00</ establishmenthour>
    <ExpirationDate>2017-02-22</ExpirationDate/>
    <acc/>
    <identification>170610015-01</identification>
  </order>

I would like to read the texte file and for any « id » that match to the xml file i twill add the expiration date.

This is what I tried :

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>
      <xsl:template match="version">
        <xsl:copy>
          <xsl:apply-templates select="*"/>
          <xsl:apply-templates    select="document('2.xml')/Orderfile/order/*" />
        </xsl:copy>
      </xsl:template>

    </xsl:stylesheet>

But that’s not working  can you please help me.

6
  • In fact it could be the first step, If I find a way to do it with the hard coded values I will be aware that it can be done. Then I will generate a new xslt with a bash script (copy-past while modifying the values). Commented May 2, 2017 at 14:29
  • Do you have any control over the "texte" file? It would be much easier if that was an XML file. In XSLT 1.0, you use the document function to access other files, but the file would need to be XML. It would also be easier to match up the ids if it were XML. Commented May 2, 2017 at 14:51
  • id(170610009-01) is computing 170610009 minus 01 and then callin the id function on the result so that is nonsense. Furthermore the id function works only with a DTD defining ID attributes. In general you are better off moving to XSLT 2.0 where you can use unparsed-text to read in a text file, use regular expressions with tokenize and/or xsl:analyze-string and then you would match on the data as necessary. Commented May 2, 2017 at 14:53
  • Check out this link: stackoverflow.com/questions/20109910/… I suggest figuring out how to handle the text as your first step. Can you get the text into well form XML before hand? Then this rule becomes easier. Commented May 2, 2017 at 14:56
  • Yes I have a control on the text file I will try transform it on xml file. @MartinHonnen id is used for my example, in real the node is called identification. Is it change something. I never used xslt 2.0 do you have an exemple to show me how it works ? Commented May 2, 2017 at 14:57

1 Answer 1

2

Here is how you could solve it with XSLT 2.0 using unparsed-text to read in and tokenize to parse the data in the text file:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:param name="text-uri" select="'input.txt'"/>
    <xsl:param name="lines" select="tokenize(unparsed-text($text-uri), '\r?\n')"/>
    <xsl:param name="data" select="for $line in $lines return tokenize($line, ';')"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="order[id = $data[position() mod 2 = 1]]/ExpirationDate">
        <xsl:copy>
            <xsl:value-of select="$data[index-of($data, current()/../id) + 1]"/>
        </xsl:copy>     
    </xsl:template>

</xsl:stylesheet>

XSLT 2.0 is supported by various tools like oXygen, Stylus Studio, Altova XMLSpy and stand-alone processors like Saxon 9, XmlPrime, Exselt.

Now that you have changed the question to use two XML input documents you could use XSLT 1.0 as follows:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:param name="data-uri" select="'input2.xml'"/>
    <xsl:param name="data-doc" select="document($data-uri)"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ExpirationDate">
        <xsl:copy>
            <xsl:variable name="match" select="$data-doc//order[identification = current()/../identification]/ExpirationDate"/>
            <xsl:choose>
                <xsl:when test="$match">
                    <xsl:value-of select="$match"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>     
    </xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for you answer, in fact I'm using xmlstarlet and I don't think it works with xslt 2.0. Maybe I should use one of your solution.
Martin, why did you make lines and data param's?
@Bluewood66, I could have made them variables instead but for flexbility used parameters instead, so an application using Saxon from Java or .NET has the choice to pass in the text file uri or the data in some other formats like string sequences.
@Martin Honnen. I've seen that before, and wasn't quite sure why. Thanks for the answer. It helps.
@Rflow, as you have changed to input format to XML I have added a solution using XSLT 1.0 and the document function.
|

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.