Transfer XML file with a languages section to a database table using XSLT - sql-server

below is a part of the xml file I get. I want to transfer this to a single mssql database table. My problem are the different languages of each job-element. The three languages below won't change in time.
I want to create 2 columns for each language in the db-table.
Example: EnglishTitle & EnglishDescription
<jobs>
<job nr="1">
<language name="English">
<title>English title</title>
<description>
<li>English description</li>
<li>English description 2</li>
<li>English description 3</li>
</description>
</language>
<language name="German">
<title>German title</title>
<description>German description</description>
</language>
<language name="Chinese">
<title>Business Mission Chinese</title>
<description>German description</description>
</language>
<general>For all languages</general>
</job>
</jobs>
How can I use XSLT to lookup the language name attribute and create two elements for each language with the content of the name attribute?
UPDATE:
This is what I think the output should look like:
<jobs>
<job nr="1">
<EnglishTitle>English title</EnglishTitle>
<EnglishDescription>
<li>English description</li>
<li>English description 2</li>
<li>English description 3</li>
</EnglishDescription>
<GermanTitle>German title</GermanTitle>
<GermanDescription>German description</GermanDescription>
<ChineseTitle>Business Mission Chinese</ChineseTitle>
<ChineseDescription>Chinese description</ChineseDescription>
<general>For all languages</general>
</job>
</jobs>
Additionally how should I store the <li>-Elements
of a description in the table? Should I replace them with new lines or with a special character?
If there is a better way feel free to tell me.

IMHO, you should have a separate row for each individual description, with columns describing the job number (hopefully unique), the language and the description itself. So something like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/jobs">
<table>
<xsl:for-each select="job/language/description/text() | job/language/description/li ">
<row>
<col><xsl:value-of select="ancestor::job/#nr"/></col>
<col><xsl:value-of select="ancestor::language/#name"/></col>
<col><xsl:value-of select="."/></col>
</row>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
which in your example would return:
<?xml version="1.0" encoding="utf-8"?>
<table>
<row>
<col>1</col>
<col>English</col>
<col>English description</col>
</row>
<row>
<col>1</col>
<col>English</col>
<col>English description 2</col>
</row>
<row>
<col>1</col>
<col>English</col>
<col>English description 3</col>
</row>
<row>
<col>1</col>
<col>German</col>
<col>German description</col>
</row>
<row>
<col>1</col>
<col>Chinese</col>
<col>German description</col>
</row>
</table>

Related

Snippet to create Snippet in SSMS

Problem:
Usually, if you want to save your code as a snippet, you have to open some xml template, investigate tags etc. Reference
Is it possible to simplify this process as much as possible: i.e. create a SurroundsWith snippet that will wrap selected code by snippet code?
Please try following:
Save this code as a create_new_snippet.snippet and add it to your SSMS through code snippet manager (Ctrl+K, Ctrk+B)
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Create_new_snippet</Title>
<Shortcut></Shortcut>
<Description>Snippet to create a snippet</Description>
<Author>Denis Sipchenko</Author>
<SnippetTypes>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal> <ID>Title</ID> <Default>NewSnippetTitle</Default> <ToolTip>NewSnippetTitle</ToolTip> </Literal>
<Literal> <ID>Description</ID> <Default>NewSnippetDescription</Default> <ToolTip>NewSnippetDescription</ToolTip> </Literal>
<Literal> <ID>Author</ID> <Default>Unsung Hero</Default> <ToolTip>NewSnippetAuthor</ToolTip> </Literal>
<Literal> <ID>SnippetType</ID> <Default>SurroundsWith</Default> <ToolTip>SurroundsWith OR Expansion</ToolTip> </Literal>
<Literal> <ID>CodeComment</ID> <Default>-- Sorry. I was too lazy to write some usefull comment here</Default> <ToolTip>Comment for you code</ToolTip> </Literal>
</Declarations>
<Code Language="sql"
Delimiter="`">
<![CDATA[<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>`Title`</Title> <!--`Title`.snippet -copy/paste for filename-->
<Shortcut></Shortcut>
<Description>`Description`</Description>
<Author>`Author`</Author>
<SnippetTypes>
<SnippetType>`SnippetType`</SnippetType> <!--SurroundsWith/Expansion-->
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal> <ID></ID> <Default></Default> <ToolTip></ToolTip> </Literal>
</Declarations>
<Code Language="SQL">
<![CDATA[`CodeComment`
$selected$`selected`$end$`end`
]]`fake`>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Select your code (that you want to save as a snippet) and call Surround With... snippet (Edit\IntelliSense\Surround With... Ctrl+K, Ctrl+S)
Edit parameters if necessary (as Title, Description etc...) and save as [YourSnippetName].snippet into your snippet folder.

How to supply unit_count_type and unit_count Amazon product data feed?

I supplied value of unit of Measure and Unit count in _POST_PRODUCT_DATA_ feed.
XmlElement unitOfMeasure = xmlDocument.CreateElement("unitOfMeasure");
unitOfMeasure.InnerText = "Count";
Product.AppendChild(unitOfMeasure);
XmlElement UnitCount = xmlDocument.CreateElement("UnitCount");
UnitCount.InnerText = "1";
Product.AppendChild(UnitCount);
My xml feed looks like this
<?xml version="1.0" encoding="iso-8859-1"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>xxxxxxx</MerchantIdentifier>
</Header>
<MessageType>Product</MessageType>
<PurgeAndReplace>false</PurgeAndReplace>
<Message>
<MessageID>1</MessageID>
<OperationType>Update</OperationType>
<Product>
<SKU>book1568388578</SKU>
<StandardProductID>
<Type>ASIN</Type>
<Value>1568388578</Value>
</StandardProductID>
<ProductTaxCode>A_GEN_NOTAX</ProductTaxCode>
<unitOfMeasure>count</unitOfMeasure>
<UnitCount>1</UnitCount>
<DescriptionData>
<Title>Relapse Prevention Long-term Workbook</Title>
<Brand> </Brand>
<Description> </Description>
<BulletPoint> </BulletPoint>
<BulletPoint> </BulletPoint>
<MSRP currency="USD">70.74</MSRP>
<Manufacturer>Hazelden Foundation,U.S.</Manufacturer>
<ItemType>books</ItemType>
</DescriptionData>
<ProductData>
<Health>
<ProductType>
<HealthMisc>
<Ingredients>Example Ingredients</Ingredients>
<Directions>Example Directions</Directions>
</HealthMisc>
</ProductType>
</Health>
</ProductData>
</Product>
</Message>
</AmazonEnvelope>
I am getting following error in feed result.
XML Parsing Error at Line 19, Column 22: cvc-complex-type.2.4.a: Invalid content was found starting with element &apos;unitOfMeasure&apos;. One of &apos;{LaunchDate, DiscontinueDate, ReleaseDate, ExternalProductUrl, Condition, Rebate, ItemPackageQuantity, NumberOfItems, LiquidVolume, DescriptionData, DiscoveryData, ProductData, ShippedByFreight, EnhancedImageURL, Amazon-Vendor-Only, Amazon-Only, RegisteredParameter, NationalStockNumber, UnspscCode, UVPListPrice}&apos; is expected.
I got the solution. You need to provide this feed of unit count in HealthMisc
Correct xml..
<?xml version="1.0" encoding="iso-8859-1"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>xxxxxxxxxx</MerchantIdentifier>
</Header>
<MessageType>Product</MessageType>
<PurgeAndReplace>false</PurgeAndReplace>
<Message>
<MessageID>1</MessageID>
<OperationType>Update</OperationType>
<Product>
<SKU>book1568388578</SKU>
<StandardProductID>
<Type>ASIN</Type>
<Value>1568388578</Value>
</StandardProductID>
<ProductTaxCode>A_GEN_NOTAX</ProductTaxCode>
<DescriptionData>
<Title>Relapse Prevention Long-term Workbook</Title>
<Brand> </Brand>
<Description> </Description>
<BulletPoint> </BulletPoint>
<BulletPoint> </BulletPoint>
<MSRP currency="USD">70.74</MSRP>
<Manufacturer>Hazelden Foundation,U.S.</Manufacturer>
<ItemType>books</ItemType>
</DescriptionData>
<ProductData>
<Health>
<ProductType>
<HealthMisc>
<UnitCount unitOfMeasure="Count">1</UnitCount>
<Ingredients>Example Ingredients</Ingredients>
<Directions>Example Directions</Directions>
</HealthMisc>
</ProductType>
</Health>
</ProductData>
</Product>
</Message>
</AmazonEnvelope>

Replace XML Span Element with Inner text of Span Tag in SQL Server

Replace span Element with its inner text whose class is "TAGGED_ITEM " in multiple rows with a column of type XML
<Item title="1234" xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2">
<ItemBody>
<div class="item_text">
<div>
<span class="TAGGED_ITEM " id="c1_ae1">This is a map on a grid.</span>
<span class="TAGGED_ITEM " id="c1_ae2"> It shows a car.</span>
</div>
<span class="TAGGED_ITEM " id="c1_ae3"> It shows a car on Road.</span>
</div>
</ItemBody>
</Item>
Once Element is updated it should looks as below.
<Item title="1234" xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2">
<ItemBody>
<div class="item_text">
<div>
This is a map on a grid.
It shows a car.
</div>
It shows a car on Road.
</div>
</ItemBody>
</Item>
This question had a particular namespace problem which, probably, had aroused the question. Eliminating namespaces on the match= does solve the problem. So an identity transform and a namespace-neutral matching gives the desired result:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[local-name() = 'span']">
<xsl:value-of select="text()" />
</xsl:template>
</xsl:stylesheet>
Result:
<?xml version="1.0"?>
<Item xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2" title="1234">
<ItemBody>
<div class="item_text">
<div>
This is a map on a grid.
It shows a car.
</div>
</div>
</ItemBody>
</Item>

How to make NewsList from News package show news as list

I'am calling the NewsList (from the standard Composite.News package) from a template like this:
<f:function name="Composite.News.NewsList" xmlns:f="http://www.composite.net/ns/function/1.0">
<f:param name="ListOptions" value="Show date,Show teaser" />
<f:param name="PageSize" value="10" />
<f:param name="DateFormat" value="dddd, MMMM dd, yyyy" />
</f:function>
I can't make it to show the news as a list. It only shows the first newsitem in the detailsmode.
What does the below line in the NewsList function do?
How can I make the control show my news in a list and not the first (most recent) item?
I have talked to a more experienced Composite Developer and he couldn't either make the Composite.News.Newslist show news in a list.
UPDATE:
I can se that the OMNICORP site doesn't use the standard News package. What is the reason for that?
Omnicorp Demo Site has its own News module based on global data type "Omnicorp.Content.News" and XSLT function "Omnicorp.Content.News"
Composite.News package is different and based on page data folder named "Composite.News.NewsItem" and two XSLT functions: "Composite.News.NewsList" and "Composite.News.NewsTeasers". So to use this package you should follow the steps described here - http://docs.composite.net/Packages/CompositeNews: create a page with page type = "News page". Add news item to the News page data folder (under the page). On the Content tab, have the Composite.News.NewsList function, which will render News List with links to the details.
But can I make the NewsTeasers list all the news and set up paging as well?
Yes you can. You can modify the existent NewsTeaser function or create the new function. On the Function Call tab modify the "Composite.News.NewsItem.GetNewsItemXml" function call and specify next parameters "PageNumber" and "IncludePagingInfo" with next values:
<f:param name="PageNumber">
<f:function name="Composite.Web.Request.QueryStringIntegerValue">
<f:param name="ParameterName" value="Page" />
<f:param name="FallbackValue" value="1" />
</f:function>
</f:param>
<f:param name="IncludePagingInfo" value="True" />
On the function Template tab add template to display PagingInfo:
<xsl:param name="pagingInfo" select="/in:inputs/in:result[#name='GetNewsItemXml']/PagingInfo" />
...
<xsl:if test="$pagingInfo/#TotalPageCount > 1">
<div class="Paging">
<xsl:apply-templates select="$pagingInfo" />
</div>
</xsl:if>
...
<xsl:template match="PagingInfo">
<xsl:param name="page" select="1" />
<xsl:if test="$page < #TotalPageCount + 1">
<xsl:if test="$page = #CurrentPageNumber">
<span><xsl:value-of select="$page" /></span>
</xsl:if>
<xsl:if test="not($page = #CurrentPageNumber)">
<xsl:value-of select="$page" />
</xsl:if>
<xsl:apply-templates select=".">
<xsl:with-param name="page" select="$page+1" />
</xsl:apply-templates>
</xsl:if>
</xsl:template>
For more information how to add Paging to the XSLT read this article- http://docs.composite.net/XSLT/SortingAndPaging

SQL XML Insert multiple elements

Please help! I have a field of xml within a database. I am trying to insert a new element for each element in the field. E.g:
<some-element>
<a> </a>
<b> </b>
</some-element>
<some-element>
<a> </a>
<b> </b>
</some-element>
would insert element c and go to:
<some-element>
<a> </a>
<b> </b>
<c> </c>
</some-element>
<some-element>
<a> </a>
<b> </b>
<c> </c>
</some-element>
I know I can use #fieldname.modify('insert #CElement into (/some-element)[1]') but this only changes the first element! I want to repeat this for all elements.
Any help would be very much appreciated! (I am using SQL server 2008)
Moved from answer:
Thank you for your reply! Perhaps it would help if I was more specific... I am describing a simple table of data within the xml. I am trying to add a new column. I can add the column within the column descriptions but I need to add the column element to all the rows. (It would not be a simple task to change the structure and I would like to avoid this!) E.g:
<Table>
<Columns>
<Column ID="0">
<Column-Name>0NAME</Column-Name>
</Column>
<Column ID="1">
<Column-Name>1NAME</Column-Name>
</Column>
<Column ID="2">
<Column-Name>2NAME</Column-Name>
</Column>
<Column ID="3">
<Column-Name>!!!! THIS COLUMN IS BEING ADDED !!!!!</Column-Name>
</Column>
</Columns>
<Rows>
<Row ID="0">
<C ID="0">0 contents here</C>
<C ID="1">0 contents here</C>
<C ID="2">0 contents here</C>
<!-- NEW COLUMN NEEDS TO BE CREATED HERE -->
</Row>
<Row ID="1">
<C ID="0">1 contents here</C>
<C ID="1">1 contents here</C>
<C ID="2">1 contents here</C>
<!-- NEW COLUMN NEEDS TO BE CREATED HERE -->
</Row>
<Row ID="2">
<C ID="0">2 contents here</C>
<C ID="1">2 contents here</C>
<C ID="2">2 contents here</C>
<!-- NEW COLUMN NEEDS TO BE CREATED HERE -->
</Row>
</Rows>
</Table>
You can recreate your XML, e.g.:
declare #x xml = '<some-element>
<a>1</a>
<b>2</b>
</some-element>
<some-element>
<a>3</a>
<b>4</b>
</some-element>'
select #x.query
('
for $e in some-element
return
<some-element>
{ $e/a }
{ $e/b }
<c/>
</some-element>
')
Adapting the answer provided by Kirill Polishchuk to the new XML structure:
select #XML.query
('
for $c in Table/Columns
return
<Table>
<Columns>
{ $c/* }
</Columns>
<Rows>
{
for $r in Table/Rows/Row
return
<Row>
{ $r/* }
<C ID="3"/>
</Row>
}
</Rows>
</Table>
')

Resources