I tryng to making a complex mapping (complex to me) with the follow scenario:
In:
<root>
<bigrow>
<row>1</row>
<row>second</row>
<row>third</row>
</bigrow>
<bigrow>
<row>4</row>
<row>rowvalue</row>
<row>anotherrowvalue</row>
</bigrow>
</root>
Out:
<entities>
<entity>
<atributeA>1</atributeA>
<atributeB>some</atributeB>
<atributeC>value</atributeC>
</entity>
<entity>
<atributeA>2</atributeA>
<atributeB>another</atributeB>
<atributeC>valuee</atributeC>
</entity>
<entity>
<atributeA>3</atributeA>
<atributeB>ooother</atributeB>
<atributeC>valueee</atributeC>
</entity>
</entities>
I want to map the row elements from the entry in order, so the desired result needs to be something like this:
<entities>
<entity>
<atributeA>1</atributeA>
<atributeB>second</atributeB>
<atributeC>third</atributeC>
</entity>
<entity>
<atributeA>4</atributeA>
<atributeB>rowvalue</atributeB>
<atributeC>anotherrowvalue</atributeC>
</entity>
</entities>
I create the map making the entry and the output as a XML and generating the schemas from this two xml and the dataMapper window looks like that:
http://i.stack.imgur.com/6CYrR.png
I cant find how to make this to work... If somebody can help me on this yuo can make me happy =)
Mule comes with an XSL-T transformer so, in case you're interested, here is the transformation that achieves your goal without using the heavy artillery of DataMapper.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<entities>
<xsl:apply-templates />
</entities>
</xsl:template>
<xsl:template match="bigrow">
<entity>
<atributeA>
<xsl:value-of select="child::row[position()=1]/text()" />
</atributeA>
<atributeB>
<xsl:value-of select="child::row[position()=2]/text()" />
</atributeB>
<atributeC>
<xsl:value-of select="child::row[position()=3]/text()" />
</atributeC>
</entity>
</xsl:template>
</xsl:stylesheet>
Related
I would like to convert the following xml to JSON:
<?xml version='1.0' encoding='utf-8'?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<array key="ids">
<number>3218087</number>
</array>
</map>
using
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:value-of select="xml-to-json(.)" />
</xsl:template>
</xsl:stylesheet>
This gives me:
{"ids":[3.218087E6]}
What I need is
{"ids":[3218087]}
Any help would be highly appreciated.
Cheers
Przemek
The spec https://www.w3.org/TR/xpath-functions/#func-xml-to-json for a number element suggests:
An element $E named number results in the output of the string result
of xs:string(xs:double(fn:string($E)))
and the cast to xs:string requires the E notation for values greater than 1000000 I think (https://www.w3.org/TR/xpath-functions/#casting-to-string).
So I don't think the xml-to-json result can be changed, unless a processor allows some options to choose a different formatting rule for numbers.
I'm very much new to JSON and have little knowledge on XML. I have a question regarding data transformation from text to XML or JSON. I've already worked with XSL Transformations, wherein I transform an XML document to either XML or text. But now, I wanted to do other way around, i.e., text -> JSON/XML
For example, I have the following text:
One(A,B) One(A',B)
Two(C,D) Two(C',D)
Three(E,F) Three(E',F)
Four(G,H)
Five(I,J)
Hence the corresponding XML output may look like:
<B> A,A' </B>
<D> C,C' </D>
<F> E,E' </F>
<H> G </H>
<J> I </J>
I hope the question is clear, if not please let me know.
Thanks in advance.
Here is an XSLT 3.0 stylesheet you can use with Saxon 9.8 or Altova XMLSpy/Raptor:
<?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"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="xs math fn"
version="3.0">
<xsl:param name="input-uri" as="xs:string" select="'input1.txt'"/>
<xsl:output indent="yes"/>
<xsl:template name="xsl:initial-template">
<xsl:apply-templates select="unparsed-text-lines($input-uri)"/>
</xsl:template>
<xsl:template match=".[. instance of xs:string]">
<xsl:for-each-group select="analyze-string(., '\w+\(([^,]*),(\w+)\)')//fn:match" group-by="fn:group[#nr = 2]">
<xsl:element name="{current-grouping-key()}">
<xsl:value-of select="current-group()/fn:group[#nr = 1]" separator=","/>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
I am studying XSL and I have question about replacing specific character in string.
we have xml file
<family>
-<familyid id="first">
--<name>smith</name>
--<image>fatherpic\myfather.jpg</image>
and i would like get image path to insert picture.
For example, we have path "fatherpic\myfather.jpg"
then i would like select "fatherpic/myfather.jpg"
which mean i would like to change"/" to"\".
i was trying to use translate function. but it didn't work.
does any can give example ? thanks
The following xslt will print replace the '\' with '/' in the image element and will print the rest of the xml file unchanged.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" />
</xsl:copy>
</xsl:template>
<xsl:template match="image">
<image>
<xsl:value-of select="translate(., '\', '/')" />
</image>
</xsl:template>
</xsl:stylesheet>
As you said in your post, you could use the translate function.
The following stylesheet extracts the value of the image value and outputs it like text after doing the described string translation. This is just an example of how to use the translate function.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" />
<xsl:template match="text()" />
<xsl:template match="image">
<xsl:value-of select="translate(., '\', '/')" />
</xsl:template>
</xsl:stylesheet>
Hope it helps.
I have a XML produce with MySQL Query Browser.
I'm trying to apply a XSLT to output the result into Word tables. One table for each record.
Here's a sample of my XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ROOT SYSTEM "Nessus.dtd">
<ROOT>
<row>
<field name="Niveau">Critique</field>
<field name="Name">Apache 2.2 < 2.2.15 Multiple Vulnerabilities</field>
</row>
<row>
<field name="Niveau">Critique</field>
<field name="VulnName">Microsoft Windows 2000 Unsupported Installation Detection</field>
</row>
<row>
<field name="Niveau">Haute</field>
<field name="VulnName">CGI Generic SQL Injection</field>
</row>
</ROOT>
For the XLST I've already found out that I need to do a for-each select
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="ROOT/row">
Niveau : <xsl:value-of select="????"/>
Name : <xsl:value-of select="????"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When I do this loop I see the same number of empty table as there is <row></row> in my file.
But I haven't found the way to make the right "value-of select=". I've try the following without luck.
<xsl:value-of select="#name"/>
<xsl:value-of select="name"/>
<xsl:value-of select="#row/name"/>
<xsl:value-of select="row/#name"/>
<xsl:value-of select="#ROOT/row/name"/>
And a few other that I can't remember. Any idea what I need to craft the request to get the value in my resulting file?
I've just tried with :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="ROOT/row">
Niveau : <xsl:value-of select="field/#Niveau"/>
Name : <xsl:value-of select="field/#name"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
And it output this :
NIVEAU :
NAME : name
NIVEAU :
NAME : Niveau
NIVEAU :
NAME : Niveau
I would like this output :
NIVEAU : Critique
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
Any help would be appreciated.
Thank you.
UPDATE
Now with this XSLT
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="row">
<xsl:text>NIVEAU : </xsl:text>
<xsl:value-of select="field[#name = 'Niveau']"/>
<xsl:text>
</xsl:text>
<xsl:text>NAME : </xsl:text>
<xsl:value-of select="field[#name = 'Name']"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
I get this output :
<?xml version="1.0"?>
NIVEAU :
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
As you can see the first field is empty. I could honestly live with that and fill it manually but if you see why this is happenning I'd be very happy :)
UPDATE
Using <xsl:value-of select="field[#name = 'foo']"/> gave me the value I wanted. I kept the for-each as it was easier to use (for me) inside a MS Word template.
for-each is generally code smell in XSLT. You most likely want a template, not a for-each loop:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="field">
<xsl:value-of select="#name"/> : <xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
This template will produce the following output:
<root>
Niveau : Critique
name : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
Niveau : Critique
name : Microsoft Windows 2000 Unsupported Installation Detection
Niveau : Haute
name : CGI Generic SQL Injection
</root>
XSLT was designed for this pattern of use--many xsl:templates matching a small part of the source and applying other templates recursively. The most important and common template in this pattern is the identity template, which copies output. This is a good tutorial on XSLT coding patterns that you should read.
Update
Below is a complete solution that will produce text output (since that is what you seem to want, not XML output). I'm not sure xsl is the best language for this, but it works....
Notice that the only place we use for-each is for sorting to determine the length of the longest name. We use templates and pattern-matching selects to make all other loops implicit.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="newline"><xsl:text>
</xsl:text></xsl:variable>
<!-- determine the maximum length of the "name" field so we can pad with spaces for all shorter items -->
<xsl:variable name="max_name_len">
<xsl:for-each select="ROOT/row/field/#name">
<xsl:sort select="string-length(.)" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="string-length(.)"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- for each row, apply templates then add a blank line -->
<xsl:template match="row">
<xsl:apply-templates/>
<xsl:value-of select="$newline"/>
</xsl:template>
<!-- for each field, apply template to name and add value, followed by a newline -->
<xsl:template match="field">
<xsl:apply-templates select="#name"/> : <xsl:value-of select="concat(., $newline)"/>
</xsl:template>
<!-- for each name, uppercase and pad with spaces to the right -->
<xsl:template match="field/#name">
<xsl:call-template name="padright">
<xsl:with-param name="text">
<xsl:call-template name="toupper">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="len" select="$max_name_len"/>
</xsl:call-template>
</xsl:template>
<!-- Utility function: uppercase a string -->
<xsl:template name="toupper">
<xsl:param name="text"/>
<xsl:value-of select="translate($text, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
</xsl:template>
<!-- Utility function: pad a string to desired len with spaces on the right -->
<!-- uses a recursive solution -->
<xsl:template name="padright">
<xsl:param name="text"/>
<xsl:param name="len"/>
<xsl:choose>
<xsl:when test="string-length($text) < $len">
<xsl:call-template name="padright">
<xsl:with-param name="text" select="concat($text, ' ')"/>
<xsl:with-param name="len" select="$len"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This stylesheet produces the following output:
NIVEAU : Critique
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
When you do <xsl:for-each select="ROOT/row">, the current context inside the loop is the rowelement. So in order to access the field name, you need to write, for example, <xsl:value-of select="field/#name"/>.
Since your XML contains several fields, you will still have to extend your XSLT file somewhat to iterate the fields, or (as Francis Avila suggested) write a template. Both methods are ok, though. The technical terms for the two approaches are "pull" and "push", respectively.
And of course, since you ultimately want to generate a word table, you will have to generate w:tr and w:tc elements, etc.
This stylesheet will give you exactly your desired output
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="row">
<xsl:text>NIVEAU : </xsl:text>
<xsl:value-of select="field[#name eq 'Niveau']"/>
<xsl:text>
</xsl:text>
<xsl:text>NAME : </xsl:text>
<xsl:value-of select="field[#name eq 'VulnName']"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
This is very specific to your input xml and output text, for example any <field> children of <row> other than 'Niveau' or 'VulnName' will be dropped from your report. A more generic solution could look like this:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:template match="field">
<xsl:value-of select="concat(upper-case(#name),': ',.)"/>
</xsl:template>
</xsl:stylesheet>
This solution though doesn't exactly match the whitespace formatting in your desired output, but it does capture all possible fields.
I have a query:
SELECT top 0 * FROM sometable FOR XML AUTO, ELEMENTS, XMLSCHEMA ('MyURI')
This query returns a schema:
<xsd:element name="ClientName">
<xsd:simpleType>
<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
<xsd:maxLength value="50" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
but I want something more like this:
<xsd:element name="ClientName">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="50" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
How can I achieve this?
You can use a XSL transform to change the SQL Server types back to the desired XSD types.
How apply the transform depends on your application. If you are creating static schemata for your tables, then you can use something like Visual Studio or msxsl. If this is a routine request from the server, then Applying an XSL Transformation (SQLXML Managed Classes) may be a better fit.
A style sheet you can build on with additional types is:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes"
xmlns="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="Strip">false</xsl:param>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#base">
<xsl:attribute name="{name()}">
<xsl:choose>
<xsl:when test=".='sqltypes:nvarchar'">xsd:string</xsl:when>
<!-- Add additional tests here -->
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>
<xsl:template match="#sqltypes:*">
<xsl:if test="$Strip=true">
<xsl:comment>
<xsl:text>Stripped (</xsl:text>
<xsl:value-of select="concat(name(), '="', ., '"')"/>
<xsl:text>)</xsl:text>
</xsl:comment>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Change the Strip parameter at the beginning to false if you need to see the attributes that are stripped in the transformation process.