XSLT - how to put original XML into transformation result in text output mode - tsql

i am trying to create a transformation which output will be text but including original xml as well. Simply i got the xml message that should be transformed to SQL insert but in case of an SQL error i want to insert the original xml message to database as well.
The input is e.g.:
<message><tag name="foo">dummy</tag></message>
The result of the transformation should be then:
INSERT INTO table (column) VALUES ('dummy')
IF ##error <> 0
BEGIN
INSERT INTO errMsgLog (message) VALUES ('<message><tag name="foo">dummy</tag></message>')
END
The problem is if i set the output in XSLT to 'text' there are no xml tags included (just the values). So is there any mixed output mode or attribute override?
Thanks for any help.

Before approaching this solution (don't know if through XSLT you can find some better solution), also consider the problems you will encounter with much more complex input and output.
Even if purists will reject this answer (and the question also), you can use "xml" output method to do a (very ugly) trickery:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:text disable-output-escaping="yes">INSERT INTO table (column) VALUES ('dummy')
IF ##error <> 0
BEGIN
INSERT INTO errMsgLog (message) VALUES ('</xsl:text>
<xsl:copy-of select="."/><xsl:text>')
END</xsl:text>
</xsl:template>
</xsl:stylesheet>
outputs:
INSERT INTO table (column) VALUES ('dummy')
IF ##error <> 0
BEGIN
INSERT INTO errMsgLog (message) VALUES ('<message><tag name="foo">dummy</tag></message>')
END

Some processors (e.g. Saxon) have an extension function serialize() which allows you to convert an XML node into a serialised XML representation, which the function returns as a string. You could call this and then output it in your text result. If your processor doesn't have such an extension function, then it might not be difficult to write one.

Related

Convert Flexform XML string from database to array, convert array to Flexform XML string to write to database in TYPO3

Question: How to convert Flexform XML to a data format where settings can be migrated and then write it back to DB. Are there some pitfalls or things I have to consider? Is there any reason not to just use GeneralUtility::xml2array() and GeneralUtility::array2Xml?
TYPO3 v11 / v12.
More details:
This is a common use case for me in my extensions: Often the schema of the Flexform is changed to improve usability. For the sake of the editors I want to migrate existing values to the new fields.
This would be pretty straightforward (in an Upgrade Wizard or Command):
Get the XML string representation from $row['pi_flexform']
Convert it to an array
Make the changes in the array
Convert it again to an XML string representation
If this is different from previous, write to $row['pi_flexform'].
The problem is figuring out which TYPO3 functions to use. There is FlexFormService, FlexFormTools and there is GeneralUtility::xml2array() and GeneralUtility::array2Xml.
The simplest solution seems to be to use array2xml and xml2array.
The second problem is figuring out what is valid XML for Flexform (unless the functions already take care of that).
Let's say I had something like this in pi_flexform which should be converted:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3FlexForms>
<data>
<sheet index="sDEF">
<language index="lDEF">
<field index="settings.foo">
<value index="vDEF">content of foo</value>
</field>
...
I don't really need the language index but that is how it looks now.
The foo field is gone in the new Flexform and the content should be converted to:
....
<field index="settings.bar">
<value index="vDEF">content of foo</value>
</field>
...
The real use case is more complicated and actually makes sense ;-)
Unfortunately, the API is not so clear.
use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
use TYPO3\CMS\Core\Service\FlexFormService;
Convert XML to array: Solution 1
$xml = $this->flexformTools->cleanFlexFormXML('tt_content', 'pi_flexform', $row);
$xmlArray = $this->flexformTools->cleanFlexFormXML;
Result: If the Flexform schema only contains the new fields, the old fields are removed - so we can't use this if the schema changes
Convert XML to array: Solution 2
$xml = $row['pi_flexform'];
$this->flexformService->convertFlexFormContentToArray($xml);
Result: This works, but the resulting $xmlArray looks like this ['settings' => ['foo' => ...
can be used for flexforms with settings but probably not best choice if is to be written again
Convert XML to array:
solution 3
$xml = $row['pi_flexform'];
$xmlArray = \TYPO3\CMS\Core\Utility\GeneralUtility::xml2array($xml)
Unclear: what should be in second and third parameter?
the result actually looks good: ['data' => ['sDEF' => ['lDef' => ['settings.foo]
Write array to XML: Solution A
$xml = $this->flexformTools->flexArray2Xml($xmlArrray, true);
Write array to XML: Solution B
$xml = GeneralUtility::array2xml($xmlArrray);
Solution A would write it like this (if combined with convertFlexFormContentToArray). Apart from that they should both work.
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3FlexForms>
<settings>
<link>http://csd.informatik.uni-oldenburg.de/adam/adamMC.bib</link>
<sort>none</sort>
<sortfixed>0</sortfixed>
<filterType>none</filterType>
<filterEntries></filterEntries>
</settings>
</T3FlexForms>

How to get the values of an element by name

I am using T-SQl and xPath to query an xml doc. and I need to extract the value of an element by name
This is the way I initially implemented the code "using element indexing to access the element" but since element can have multiples element of , it does not longer work properly.
n.value(''./ROLES[1]/ROLE[1]/BORROWER[1]/GOVERNMENT_MONITORING[1]/HMDA_RACES[1][./HMDA_RACE/EXTENSION/ULDD:OTHER/ULDD:HMDA_RACE_EXTENSION/ULDD:HMDA_RACE_DETAIL/ULDD:HMDARaceType][1]'',''VARCHAR(100)'')
This is the xml I am querying
<HMDA_RACES>
<HMDA_RACE>
<EXTENSION>
<ULDD:OTHER xmlns:ULDD="http://www.datamodelextension.org/Schema/ULDD">
<ULDD:HMDA_RACE_EXTENSION>
<ULDD:HMDA_RACE_DESIGNATIONS>
<ULDD:HMDA_RACE_DESIGNATION>
<ULDD:HMDARaceDesignationType>Samoan</ULDD:HMDARaceDesignationType>
</ULDD:HMDA_RACE_DESIGNATION>
</ULDD:HMDA_RACE_DESIGNATIONS>
<ULDD:HMDA_RACE_DETAIL>
<ULDD:HMDARaceType>NativeHawaiianOrOtherPacificIslander</ULDD:HMDARaceType>
</ULDD:HMDA_RACE_DETAIL>
</ULDD:HMDA_RACE_EXTENSION>
</ULDD:OTHER>
</EXTENSION>
</HMDA_RACE>
<HMDA_RACE>
<EXTENSION>
<ULDD:OTHER xmlns:ULDD="http://www.datamodelextension.org/Schema/ULDD">
<ULDD:HMDA_RACE_EXTENSION>
<ULDD:HMDA_RACE_DETAIL>
<ULDD:HMDARaceType>White</ULDD:HMDARaceType>
</ULDD:HMDA_RACE_DETAIL>
</ULDD:HMDA_RACE_EXTENSION>
</ULDD:OTHER>
</EXTENSION>
</HMDA_RACE>
</HMDA_RACES>
this is what I am trying but I am not getting the result I want.
value(''./ROLES[1]/ROLE[1]/BORROWER[1]/GOVERNMENT_MONITORING[1]/HMDA_RACES[child = "ULDD:HMDARaceType"][1]'',''VARCHAR(100)'')
a successful query would return value "NativeHawaiianOrOtherPacificIslander White". I am getting just the first value "NativeHawaiianOrOtherPacificIslander"
Just in terms of the xpath expression, and using the xml code in your question, this expression
*//HMDARaceType/text()
or this:
//*[local-name()='HMDARaceType']/text()
selects
NativeHawaiianOrOtherPacificIslander
White
Is that what you're looking for?

How can I specialize the link element (related-links)

i'd like to create new elements, based on the link element. This would be more comfortable for the author than using the role and otherrole attributes to specify the link role.
Unfortunately the DITA-OT 2.2.1 fails with this message:
Required item type of result of template related-links:link.
is element(Q{}link); supplied value has item type
element(Q{}myelement)
Is this a valid approach, or should I stick to otherrole?
Update 1:
The error occurs in the related-links.xsl:
<!-- Ungrouped links have the default-mode
template applied to them. (Can be overridden.) -->
<xsl:template match="*[contains(#class, ' topic/link ')]"
mode="related-links:link"
name="related-links:link."
as="element(link)">
<xsl:sequence select="."/> <!--- error points to this line -->
</xsl:template>
This is clearly a bug in the XSLT implementation as you can't use direct tagname checks with any DITA processing because it will fail in the face of specialization as you're seeing.
Side note: assuming your specialization is a domain, the name for the domain should end in "-d" per the DITA naming conventions:
class="- topic/link mylink-d/mylinktype "
This is a convention not a hard requirement but it's useful to be able to look at the #class value and know if an element comes from a domain or a structural specialization.

iPhone : parse Lengthy XML file on the Base of Key Field

i want to parse the xml File. xml File structure is following
<?xml version="1.0" encoding="utf-8"?>
<Level>
<p id='327'>
<Item>
<Id>5877</Id>
<Type>0</Type>
<Icon>---</Icon>
<Title>Btn1Item1</Title>
</Item>
<Item>
<Id>5925</Id>
<Type>0</Type>
<Icon>---</Icon>
<Title>Btn1Item4</Title>
</Item>
</p>
<p id='328'>
<Item>
<Id>5878</Id>
<Type>0</Type>
<Icon>---</Icon>
<Title>Btn2Item1</Title>
</Item>
<Item>
<Id>5926</Id>
<Type>0</Type>
<Icon>---</Icon>
<Title>Btn2Item4</Title>
</Item>
</p>
</Level>
in above code there are only 2 tag for <p>. but in actual there are multiple tag. i want to search the specific tag for which attribute id have some specific value (say 327).
so one way is that i parse the XML file from start to get the desired result. whether there are any other method from which i can direct locate the desired tag. for example if i want to search the <p> tag in above XML for attribute id =328, then it does not parse the id=327 and direct return only those item which are related to id=328
Please suggest
Depends how you define "parse".
A "quick & dirty" (and potentially buggy) way would be to find the fragment using a regex search (or a custom parser) first, then feed the fragment to a true XML parser. I don't know of anything that would do this for you, you'd have to roll it yourself. I would suggest that it's not the way to go.
The next level is to feed it through a SAX-like parser (which NSXMLParser is a form of).
In your handler for the <p> element, check the id attribute and if it matches your value (or values), set a flag to indicate if child elements should be interpreted.
In your child element handlers, just check that flag first (in a raw NSXMLParser handler all elements would go to the same method, of course).
So it's true that NSXMLParser would be parsing the whole document - but just to do the minimal work to establish the correct XML parser context. The real work of handling the elements would be deferred until the value is met. I don't see any way around that without something hacky like the regex suggestion.
If this is too much overhead I'd reconsider whether XML is the right serialization format for you (assuming you have any control over that)?
If you do stick with NSXMLParser, my blog article here might help to at least make the experience nicer.
The libxml2 library can receive XPath queries with the following extensions. With these extensions you might issue the XPath query /p[#id = "328"] to retrieve that specific node's children.

Ignore CDATA while xml parsing

I am new to iphone development.I want to ignore CDATA tag while parsing because it consider the HTML tag following it as text.Since i want to display the content alone ,i want my parser to ignore CDATA tag.My source code is
[CDATA[<br /><p class="author"><span class="by">By: </span>By Sydney Ember</p><br><p>In the week since an </p>]].
Is there any way to ignore CDATA tag?
Is there any way to parse my source twice so it displays only the content?
Please give me some sample code.Please help me out.Thanks.
If you treat the CDATA content as XML instead of CDATA then your parser will throw an error (since your HTML is a weird mix of XHTML and HTML and is not well formed).
If you want to get the HTML, then parse the XML, extract the text content of the node, then parse that text as HTML.
There is no way to ignore the CDATA tag - it's part of the xml spec and parsers should honour it.
If you don't like the idea of this answer to your earlier question, you could get the contents of the CDATA section and parse it as XML again. However, this is highly not recommended! You don't know that the contents of the CDATA are going to be valid xml (they're probably not).
If you can 100% guarentee that the CDATA section contains the form you have above, you could probably use some string manipulation to get the data out (i.e. string replace '<span class="by">By: </span>' with '') but again, this will almost certainly break if the CDATA contents change.
Where is the xml coming from? It's a better idea to talk to owner of the service and get them to send you instead of description something like
<description>
<author>By Sydney Ember</autho>
<text>In the week since an </text>
</description>
S