How to map value of one xml to another one in Python - python-3.x

I need to make XML out of response in XML format.
For some fields, I need to be able to change the value. I also need to remove all fields that are not mapped.
I get responses that look like this
<response>
<DOCUMENTS>
<DOCUMENT>
<KODA>AA</KODA>
<ITEMS>
<ITEM>B</ITEM>
<ITEM>C</ITEM>
</ITEMS>
</DOCUMENT>
</DOCUMENTS>
</response>
and want to make of it something that looks like below
<EXPORT>
<DOCUMENTS>
<DOCUMENT>
<KODDZ>SS</KODDZ>
<VALUES>
<VALUE>B</VALUE>
<VALUE>C</VALUE>
</VALUES>
</DOCUMENT>
</DOCUMENTS>
</EXPORT>
I have been trying using the XSLT example from this question but without success.
Basically what would be best for me would be a solution that takes some kind of map of fields for example:
map_of_values = {"response/DOCUMENTS/DOCUMENT/KODA":"EXPORT/DOCUMENTS/DOCUMENT/KODZA",
"response/DOCUMENTS/DOCUMENT/ITEMS/ITEM":EXPORT/DOCUMENTS/DOCUMENT/VALUES/VALUE}
What would be the best way to achieve a static map kind of solution?

In terms of XSLT you seem to want something along the lines of
<xsl:template match="response">
<EXPORT>
<xsl:apply-templates/>
</EXPORT>
</xsl:template>
<xsl:template match="KODA">
<KODDZ>
<xsl:apply-templates/>
</KODDZ>
</xsl:template>
<xsl:template match="KODA/text()[. = 'AA']">
<xsl:text>SS</xsl:text>
</xsl:template>
<xsl:template match="ITEMS">
<VALUES>
<xsl:apply-templates/>
</VALUES>
</xsl:template>
<xsl:template match="ITEM">
<VALUE>
<xsl:apply-templates/>
</VALUE>
</xsl:template>
plus the identity transformation template, of course.

Related

How to map repeating xml elements in Excel

I'm dealing with a problem on how to map repeating xml elements, the moment I imported the XML below as an XML map in excel, I see only 1 for the 4 records i need "<club_LIST>" of course this doesn't produce the 4 entries in the output XML.
Any idea how can this be solved in Excel ?
I from Microsoft support:
Additionally, the contents of an XML mapping cannot be exported if the contents contain one of the following XML schema constructs:
List of lists One list of items contains a second list of items.
Any way around you could suggest to produce the xml?
Here below the sample of my data:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<PartnersProfile xmlns:xsi="http://www.w3.org/2001/xmlschema-instance">
<ID>10</ID>
<NAME>Table 10</NAME>
<Record>
<PARTNER_ID>1</PARTNER_ID>
<DESCRIPTION>customer</DESCRIPTION>
<subscription>2004</subscription>
<club_LIST>1</club_LIST>
<club_LIST>4</club_LIST>
<club_LIST>6</club_LIST>
<club_LIST>9</club_LIST>
</Record>
<Record>
<PARTNER_ID>1</PARTNER_ID>
<DESCRIPTION>customer</DESCRIPTION>
<subscription>2004</subscription>
<club_LIST>1</club_LIST>
<club_LIST>4</club_LIST>
<club_LIST>6</club_LIST>
<club_LIST>9</club_LIST>
</Record>
</PartnersProfile>
Consider transforming the XML to an itemized version by each club_LIST with repeating values for ancestor elements. You can run the below XSLT 1.0 by many tools and programming languages including Perl (from your profile) or Excel VBA.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/PartnersProfile">
<xsl:copy>
<xsl:apply-templates select="descendant::club_LIST"/>
</xsl:copy>
</xsl:template>
<xsl:template match="club_LIST">
<Record>
<xsl:copy-of select="ancestor::PartnersProfile/*[name()!='Record']"/>
<xsl:copy-of select="ancestor::Record/*[name()!='club_LIST']"/>
<club_LIST><xsl:apply-templates select="node()"/></club_LIST>
</Record>
</xsl:template>
</xsl:stylesheet>
Online Demo

hello world xml -> json template

I'm trying to transform an xml input to a json output. My XSLT 1.0 is pretty proficient my XSLT 2.0/3.0 not so.
I thought I'd start with a hello world style template and build from there.
My belief is that you can simply create an output as map/array data structure and then some magic will map that into the desired output, so this is my first attempt (I've not defined an input, because any old xml will do in this example, it ignores it):
<?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">
<xsl:output method="json" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="foo">
<map xmlns="http://www.w3.org/2005/xpath-functions">
<string key='desc'>Distances between several cities, in kilometers.</string>
<string key='updated'>2014-02-04T18:50:45</string>
<boolean key="uptodate">true</boolean>
<null key="author"/>
<map key='cities'>
<array key="Brussels">
<map>
<string key="to">London</string>
<number key="distance">322</number>
</map>
<map>
<string key="to">Paris</string>
<number key="distance">265</number>
</map>
<map>
<string key="to">Amsterdam</string>
<number key="distance">173</number>
</map>
</array>
</map>
</map>
</xsl:variable>
<xsl:value-of select="xml-to-json($foo)"/>
</xsl:template>
</xsl:stylesheet>
this almost works but I get a string output...(the '"' chars exist in the output file includeing all the escaping, so not a valid json output).
"{\"desc\":\"Distances between several cities, in kilometers.\",\"updated\":\"2014-02-04T18:50:45\",\"uptodate\":true,\"author\":null,\"cities\":{\"Brussels\":[{\"to\":\"London\",\"distance\":322},{\"to\":\"Paris\",\"distance\":265},{\"to\":\"Amsterdam\",\"distance\":173}]}}"
If there are any basic guides to do this, then please let me know, the web is awash with odd examples, out of date instruction based on XSLT 1.0/2.0 or hard to understand pdfs discussing more in depth scenarios.
The function you use already gives you a string with the JSON (see https://www.w3.org/TR/xpath-functions-31/#func-xml-to-json) so if you want to write that to a file just use <xsl:output method="text"/>.
The json output method mainly makes sense if you construct XDM/XPath 3.1 maps/arrays and want to serialize them as JSON.
For your sample I would also use <xsl:template name="xsl:initial-template"> instead of <xsl:template match="/">, then you don't need to provide any dummy input XML at all but can just start with that default named template using e.g. -it from the command line or callTemplate(null, ..) from the API.

How to keep my topics printing consecutively, without an empty page after each topic

DITA 3.6
Oxygen XML Editor 23.1
The "DITA for Print" book nor any other source, so far, has helped me produce a pdf where the topics are consecutive rather than having a blank page after them. To each topicref in the ditamap, I added outputclass="page-break-avoid". To each topic element in each file, I added outputclass="page-break-avoid".
Should I add something in an xsl file? Can you point me to the answer?
The blank page is generated from the definition fo:page-sequence/#force-page-number property.
To change not to generate blank-page, you can override org.dita.pdf2/cfg/fo/attrs/commons-attr.xsl.
<xsl:attribute-set name="__force__page__count">
<xsl:attribute name="force-page-count">
<xsl:choose>
<xsl:when test="/*[contains(#class, ' bookmap/bookmap ')]">
<xsl:value-of select="'even'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'auto'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:attribute-set>
Change the value even to auto will satisfy your needs.
Steps to customize
I'm not familiar with PDF2 plug-in. So this may not the standard way. But I could customize it by following steps.
Make customization XSL file
[DITA-OT]/plugins/org.dita.pdf2/Customization/fo/attrs/commons-attr.xsl
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:rx="http://www.renderx.com/XSL/Extensions"
version="2.0">
<xsl:attribute-set name="__force__page__count">
<xsl:attribute name="force-page-count">
<xsl:choose>
<xsl:when test="/*[contains(#class, ' bookmap/bookmap ')]">
<xsl:value-of select="'auto'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'auto'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:attribute-set>
</xsl:stylesheet>
Include it into [DITA-OT]/plugins/org.dita.pdf2/Customization/fo/attrs/custom.xsl
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="2.0">
<xsl:include href="commons-attr.xsl"/>
</xsl:stylesheet>
Customize [DITA-OT]/plugins/org.dita.pdf2/Customization/catalog.xml
<?xml version="1.0" encoding="utf-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
<!-- Custom attributes entry -->
<uri name="cfg:fo/attrs/custom.xsl" uri="fo/attrs/custom.xsl"/>
</catalog>
Specify customization.dir property with [DITA-OT]\plugins\org.dita.pdf2\Customization in Oxygen transformation scenario.
Apply transformation scenario from Oxygen.
I've got the following temp/topic.fo. The fo:page-sequence/#force-page-count became auto and in the result PDF, the redundant blank pages are removed.

XSL if test string comparison not working

I have some XML this looks like this:
<region class="TableInfo">
text
</region>
<region>
text
</region>
I want to write XSL that only preserves that part without the class="TableInfo".
I've tried a number of different ways, including:
<xsl:for-each select="region[class!='TableInfo']">
</xsl:for-each>
and
<xsl:for-each select="region">
<xsl:if test="not(class=&apos;TableInfo&apos;)">
</xsl:if>
</xsl:for-each>
and several variations thereof. it seems like it's somehow evaluating as a value rather than a string, because when I set it up as an != test, all the content gets deleted, and when I set it up as a not(), nothing gets deleted. any help?
thanks!
<xsl:for-each select="region[not(#class='TableInfo')]">
</xsl:for-each>
You forgot the # on class, so you were trying to check for class elements instead of the attributes. And apparently the != is not working as well, so I swapped in the not() function instead.
From a stylistic point, I would also suggest looking into using templates that match the region elements so you can use apply-templates instead of a for-each.
The identity rule is your friend (and of course, you need to specify the attribute class, not a "class" element):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*"><xsl:apply-templates/></xsl:template>
<xsl:template match="region[#class='TableInfo']"/>
</xsl:stylesheet>
When this transformation is applied on the provided XML (fragment wrapped into a single top element to make it a well-formed XML document):
<region>
text
</region>

How to replace text defined in a given tag or element using xslt, xslt string replace

Please help me with this xslt transformation.
Source Xml
<xml>
<test>This is a <bold>sample</bold> description. Please help me with a sample</text>
</xml>
Expected Output: This is a sample description. Please help me with a sample
I just need to make bold only the specified text by the xml markup.
Thank you
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="text">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="bold">
<b><xsl:apply-templates/></b>
</xsl:template>
</xsl:stylesheet>
when applied against the provided XML document:
<xml>
<text>This is a <bold>sample</bold> description. Please help me with a sample</text>
</xml>
produces the desired result in HTML:
<p>This is a <b>sample</b> description. Please help me with a sample</p>

Resources