mavi
mavi

Reputation: 1138

How to convert a String xml into a XML node XSLT

I´m consuming the Banxico Web Services and it returns a string, inside that string there is the XML.

What I really need is to extract the next part using XSLT or XPath.

How can do it using XSLT or Xpath?

Pesos por dólar E.U.A. Tipo de cambio para solventar obligaciones denominadas en moneda extranjera Fecha de determinación (FIX)" IDSERIE="SF43718" BANXICO_FREQ="Dia" BANXICO_FIGURE_TYPE="TipoCambio" BANXICO_UNIT_TYPE="PesoxDoll">

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <X-OPNET-Transaction-Trace:X-OPNET-Transaction-Trace soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0" xsi:type="soapenc:string" xmlns:X-OPNET-Transaction-Trace="http://opnet.com" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">pid=4468,requestid=4d0ce60a-c92f-441e-87b1-4c6f12b26574</X-OPNET-Transaction-Trace:X-OPNET-Transaction-Trace>
   </soapenv:Header>
   <soapenv:Body>
      <ns1:tiposDeCambioBanxicoResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://ws.dgie.banxico.org.mx">
         <result xsi:type="xsd:string"><![CDATA[<?xml version="1.0" encoding="ISO-8859-1"?>
<CompactData xmlns="http://www.SDMX.org/resources/SDMXML/schemas/v1_0/message"
xmlns:bm="http://www.banxico.org.mx/structure/key_families/dgie/sie/series/compact"
xmlns:compact="http://www.SDMX.org/resources/SDMXML/schemas/v1_0/compact"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.SDMX.org/resources/SDMXML/schemas/v1_0/message SDMXMessage.xsd
http://www.banxico.org.mx/structure/key_families/dgie/sie/series/compact BANXICO_DGIE_SIE_Compact.xsd
http://www.SDMX.org/resources/SDMXML/schemas/v1_0/compact SDMXCompactData.xsd" >
    <Header>
        <ID>TIPOSDECAMBIO</ID>
        <Test>false</Test>
        <Truncated>false</Truncated>
        <Name xml:lang="sp">Tipos de Cambio</Name>
        <Prepared>2016-12-15 12:26:37.766</Prepared>
        <Sender id="BANXICO">
            <Name xml:lang="sp">Banco de México</Name>
            <Contact>
            <Name xml:lang="sp">Subgerencia de Desarrollo de Sistemas</Name>
            <Telephone>(01 55)52372678</Telephone>
            </Contact>
        </Sender>
        <DataSetAction>Update</DataSetAction>
        <Extracted>2016-12-15 12:26:37.766</Extracted>
    </Header>
    <bm:DataSet>
        <bm:SiblingGroup BANXICO_FREQ="Dia" TIME_FORMAT="P1D"/>
        <bm:Series TITULO="Tipo de cambio pesos por dólar E.U.A. Tipo de cambio para solventar obligaciones denominadas en moneda extranjera Fecha de liquidación" IDSERIE="SF60653" BANXICO_FREQ="Dia" BANXICO_FIGURE_TYPE="TipoCambio" BANXICO_UNIT_TYPE="PesoxDoll">
            <bm:Obs TIME_PERIOD="2016-12-15" OBS_VALUE="20.2567"/>
        </bm:Series>
        <bm:Series TITULO="Tipo de cambio                                          Pesos por dólar E.U.A. Tipo de cambio para solventar obligaciones denominadas en moneda extranjera Fecha de determinación (FIX)" IDSERIE="SF43718" BANXICO_FREQ="Dia" BANXICO_FIGURE_TYPE="TipoCambio" BANXICO_UNIT_TYPE="PesoxDoll">
            <bm:Obs TIME_PERIOD="2016-12-15" OBS_VALUE="20.5973"/>
        </bm:Series>
        <bm:Series TITULO="Cotización de las divisas que conforman la canasta del DEG Respecto al peso mexicano Euro" IDSERIE="SF46410" BANXICO_FREQ="Dia" BANXICO_FIGURE_TYPE="TipoCambio" BANXICO_UNIT_TYPE="Peso">
            <bm:Obs TIME_PERIOD="2016-12-14" OBS_VALUE="21.535"/>
        </bm:Series>
        <bm:Series TITULO="Cotización de la divisa Respecto al peso mexicano Dólar Canadiense" IDSERIE="SF60632" BANXICO_FREQ="Dia" BANXICO_FIGURE_TYPE="TipoCambio" BANXICO_UNIT_TYPE="Peso">
            <bm:Obs TIME_PERIOD="2016-12-14" OBS_VALUE="15.4178"/>
        </bm:Series>
        <bm:Series TITULO="Cotización de las divisas que conforman la canasta del DEG Respecto al peso mexicano Yen japonés" IDSERIE="SF46406" BANXICO_FREQ="Dia" BANXICO_FIGURE_TYPE="TipoCambio" BANXICO_UNIT_TYPE="Peso">
            <bm:Obs TIME_PERIOD="2016-12-14" OBS_VALUE="0.176"/>
        </bm:Series>
        <bm:Series TITULO="Cotización de las divisas que conforman la canasta del DEG Respecto al peso mexicano Libra esterlina" IDSERIE="SF46407" BANXICO_FREQ="Dia" BANXICO_FIGURE_TYPE="TipoCambio" BANXICO_UNIT_TYPE="Peso">
            <bm:Obs TIME_PERIOD="2016-12-14" OBS_VALUE="25.5806"/>
        </bm:Series>
    </bm:DataSet>
</CompactData>]]></result>
      </ns1:tiposDeCambioBanxicoResponse>
   </soapenv:Body>
</soapenv:Envelope>

With that response I build a xsd schema.

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.banxico.org.mx/structure/key_families/dgie/sie/series/compact" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="DataSet">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="SiblingGroup">
          <xs:complexType>
            <xs:simpleContent>
              <xs:extension base="xs:string">
                <xs:attribute type="xs:string" name="BANXICO_FREQ"/>
                <xs:attribute type="xs:duration" name="TIME_FORMAT"/>
              </xs:extension>
            </xs:simpleContent>
          </xs:complexType>
        </xs:element>
        <xs:element name="Series" maxOccurs="unbounded" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Obs">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:date" name="TIME_PERIOD" use="optional"/>
                      <xs:attribute type="xs:float" name="OBS_VALUE" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute type="xs:string" name="TITULO" use="optional"/>
            <xs:attribute type="xs:string" name="IDSERIE" use="optional"/>
            <xs:attribute type="xs:string" name="BANXICO_FREQ" use="optional"/>
            <xs:attribute type="xs:string" name="BANXICO_FIGURE_TYPE" use="optional"/>
            <xs:attribute type="xs:string" name="BANXICO_UNIT_TYPE" use="optional"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Upvotes: 1

Views: 4264

Answers (2)

ade
ade

Reputation: 151

I would recommend using the JSON API https://www.banxico.org.mx/SieAPIRest instead of that old soap service.

Upvotes: 0

Eir&#237;kr &#218;tlendi
Eir&#237;kr &#218;tlendi

Reputation: 1190

To just run an XSL transformation to extract the information you want, you don't need to generate a schema.

If you can use XPath 3 functions, you can do all of this in one pass: XPath 3 includes a function to parse a string and turn it into a logical XML tree, allowing you to then run XPath expressions against that.

If you can't use XPath 3 functions, then you'll need to do this in two passes: export just the <result> text content (the XML response that you want to further process) to a separate file, and then load that file and run another transform on that to extract what you want.

Here's a quick-and-dirty example of how to process this in one pass using XPath 3.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

    <!-- Start at the document node / and set up the outermost element -->
    <xsl:template match="/">
        <!-- Change this element name to whatever makes sense for you -->
        <BanxicoReply>
            <!-- The input file only has one "result", 
                and that's all we want, so grab it -->
            <xsl:apply-templates select="//result"/>
        </BanxicoReply>
    </xsl:template>

    <xsl:template match="result">
        <!-- Parse the CDATA content to turn it into XML -->
        <xsl:variable name="contained-xml" select="parse-xml(./text())"/>

        <!-- Do what you need to here.
            This example just plucks out the one chunk
            you identified at the top of your post. 

            Note the "*:Series" shorthand: this matches
            any "Series" element in any namespace.  This 
            is an admittedly sloppy shortcut, which could
            be dangerous in other contexts - but here, in
            this one file, it's safe, and this avoids the 
            need for us to explicitly declare the "bm:" 
            namespace prefix in this XSL. -->
        <xsl:copy-of select="$contained-xml//*:Series[@IDSERIE='SF43718']"/>
    </xsl:template>

    <!-- Suppress output of all other elements -->
    <xsl:template match="*"/>

</xsl:stylesheet>

Using your XML above as the input, this XSL produces the following result (indented for easier human legibility):

<?xml version="1.0" encoding="UTF-8"?>
<BanxicoReply>
    <bm:Series xmlns="http://www.SDMX.org/resources/SDMXML/schemas/v1_0/message" 
        xmlns:bm="http://www.banxico.org.mx/structure/key_families/dgie/sie/series/compact" 
        xmlns:compact="http://www.SDMX.org/resources/SDMXML/schemas/v1_0/compact" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        TITULO="Tipo de cambio                                          Pesos por dólar E.U.A. Tipo de cambio para solventar obligaciones denominadas en moneda extranjera Fecha de determinación (FIX)" 
        IDSERIE="SF43718" 
        BANXICO_FREQ="Dia" 
        BANXICO_FIGURE_TYPE="TipoCambio" 
        BANXICO_UNIT_TYPE="PesoxDoll">
        <bm:Obs TIME_PERIOD="2016-12-15" OBS_VALUE="20.5973"/>
    </bm:Series>
</BanxicoReply>

Upvotes: 3

Related Questions