XSLT 1.0 How to get distinct values - distinct

I had an XML somewhat similar to what is shown below. I had to find the unique categories. There are lot of easy ways in XSLT 2.0. But I had to stick to 1.0 :( . After several struggle I found the solution. I thought of sharing. Might help somebody. Please improve my answer. I appreciate.
<root>
<category>
this is Games category
</category>
<category>
this is Books category
</category>
<category>
this is Food category
</category>
<category>
this is Games category
</category>
<category>
this is Books category
</category>
<category>
this is Food category
</category>
<category>
this is Travel category
</category>
<category>
this is Travel category
</category>
</root>
Solution. I have added in the answer section. Thanks.

Solution
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="test">
<xsl:call-template name="delimitedvalues">
<xsl:with-param name="paramvalues" select="//category" />
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="distinctvalues">
<xsl:with-param name="values" select="$test" />
</xsl:call-template>
</xsl:template>
<xsl:template name="distinctvalues">
<xsl:param name="values"/>
<xsl:variable name="firstvalue" select="substring-before($values, ',')"/>
<xsl:variable name="restofvalue" select="substring-after($values, ',')"/>
<xsl:if test="contains($values, ',') = false">
<xsl:value-of select="$values"/>
</xsl:if>
<xsl:if test="contains($restofvalue, $firstvalue) = false">
<xsl:value-of select="$firstvalue"/>
<xsl:text>,</xsl:text>
</xsl:if>
<xsl:if test="$restofvalue != ''">
<xsl:call-template name="distinctvalues">
<xsl:with-param name="values" select="$restofvalue" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="delimitedvalues">
<xsl:param name="paramvalues" />
<xsl:value-of select="substring-before(substring-after($paramvalues,'this is '),' category')"/>
<xsl:if test="$paramvalues/following::category">
<xsl:text>,</xsl:text>
<xsl:call-template name="delimitedvalues">
<xsl:with-param name="paramvalues" select="$paramvalues/following::category" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Output
Games,Books,Food,Travel
Source Code
http://www.xsltcake.com/slices/0iWpyI

Related

Using XSLT, is there a way to make the sort order of a nodeset match the order of a second nodeset?

I am acting on a set of documents that have a <DataTypes> area, which defines the structure of groups of primative datatypes and other structures, and a <Tags> area, which defines the values of instances of these datatypes.
Original XML
<?xml version="1.0" encoding="utf-8" ?>
<Program>
<DataTypes>
<DataType Name="String20">
<Member Name="LEN" DataType="INTEGER" Dimension="0" />
<Member Name="DATA" DataType="BYTE" Dimension="20" />
</DataType>
<DataType Name="UDT_Params">
<Member Name="InAlarm" DataType="BIT" Dimension="0" />
<Member Name="SetPoint" DataType="FLOAT" Dimension="0" />
<Member Name="DwellTime" DataType="INTEGER" Dimension="0" />
<Member Name="UserName" DataType="String20" Dimension="0" />
</DataType>
</DataTypes>
<Tags>
<Tag Name="MyParameters" DataType="UDT_Params">
<Data Name="InAlarm" DataType="BIT" Value="0" />
<Data Name="SetPoint" DataType="FLOAT" Value="4.5" />
<Data Name="DwellTime" DataType="INTEGER" Value="10" />
<Data Name="UserName" DataType="String20">
<Data Name="LEN" DataType="INTEGER" Value="3" />
<Data Name="DATA" DataType="String20" > <!--The system I'm working in shows strings as arrays of BYTES in DataType, -->
Bob <!--but calls them out as Strings when they are used as tags. I cannot change it.-->
</Data>
</Data>
</Tag>
</Tags>
</Program>
Stylesheet
<?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"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!--Packing algorithm. Works fine on datatypes, but not on Tags.-->
<xsl:template name="pack-nodes">
<xsl:param name="nodes" />
<!--Omitted for brevity-->
</xsl:template>
<!--Pack DataTypes-->
<xsl:variable name="datatypes-packed">
<xsl:call-template name="pack-nodes">
<xsl:with-param name="nodes" select="/Program/DataTypes/DataType" />
</xsl:call-template>
</xsl:variable>
<!--Write DataTypes to output.-->
<xsl:template match="/Program/DataTypes">
<xsl:copy>
<xsl:for-each select="msxsl:node-set($datatypes-packed)">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!--Pack tags-->
<xsl:variable name="tags-packed">
<xsl:call-template name="pack-nodes">
<xsl:with-param name="nodes" select="/Program/Tags/Tag" />
</xsl:call-template>
</xsl:variable>
<!--Write Tags to output.-->
<xsl:template match="/Program/Tags">
<xsl:copy>
<xsl:for-each select="msxsl:node-set($tags-packed)">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="utf-8"?>
<Program>
<DataTypes>
<DataType Name="String20">
<Member Name="LEN" DataType="INTEGER" Dimension="0"/>
<Member Name="DATA" DataType="BYTE" Dimension="20"/>
</DataType>
<DataType Name="Parameters" DataType="UDT_Params">
<Member Name="UserName" DataType="String20" Dimension="0"/>
<Member Name="SetPoint" DataType="FLOAT" Dimension="0"/>
<Member Name="DwellTime" DataType="INTEGER" Dimension="0"/>
<Member Name="InAlarm" DataType="BIT" Dimension="0"/>
</DataType>
</DataTypes>
<Tags>
<Tag Name="MyParameters" DataType="UDT_Params">
<Data Name="UserName" DataType="String20">
<Data Name="DATA" DataType="String20"> <!--Note that DATA comes before LEN -->
Bob
</Data>
<Data Name="LEN" DataType="INTEGER" Value="3"/>
</Data>
<Data Name="SetPoint" DataType="FLOAT" Value="4.5"/>
<Data Name="DwellTime" DataType="INTEGER" Value="10"/>
<Data Name="InAlarm" DataType="BIT" Value="0"/>
</Tag>
</Tags>
</Program>
My operations on the DataTypes section adds nodes and changes the node order. For the section to work correctly, the tag elements must match the contents and order of their respective datatypes, exactly.
If I keep a variable in memory of the final state of the DataSet nodes, is there a simple way to have the tag nodes look up their dataset (via the Structure and StructureMember #DataSet attributes, and sort their members accordingly?
I'm having trouble figuring out where to start.
NOTE: Transformation must be in XSLT 1.0. I'm using .Net, and don't want to introduce a lot of dependencies on external libraries.
It's a bit tricky in XSLT 1.0 (isn't everything?) but a technique that sometimes works is to construct a variable $tokens containing the list of tokens in the required order, for example "|Description|Name|ProcessEntityIndex|Severity|...", and then sort on select="string-length(substring-before($tokens, concat('|',#Name)))".
Using Michael Kay's suggesting for sorting, I ended up with the following:
Stylesheet
<?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"
>
<xsl:output method="xml" indent="yes"/>
<!--Skipped to new part -->
<xsl:template name="sort-by-datatype">
<xsl:param name="tags" />
<xsl:param name="datatypes" />
<xsl:for-each select="msxsl:node-set($tags)">
<!--First, do an edge-check.-->
<xsl:variable name="edge">
<xsl:call-template name="edge-check">
<xsl:with-param name="n1" select="." />
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<!--No children, nothing to sort. Just do a deep copy.-->
<xsl:when test="$edge = 'true'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<!--Search for datatype in the DataTypes nodeset, and use it to create a list of members in order.-->
<xsl:variable name="tag-datatype" select="./#DataType" />
<xsl:variable name="tokens-untrimmed">
<xsl:for-each select="msxsl:node-set($datatypes)/DataType[#Name = $tag-datatype]/Member">
<xsl:value-of select="concat(' | ', #Name)"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="tokens" select="substring-after($tokens-untrimmed, '|')" />
<xsl:choose>
<!--If tokens string is empty (maybe because we couldn't find the datatype?), just copy the tag as it is, then recurse.-->
<xsl:when test="string-length($tokens) = 0">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:call-template name="sort-by-datatype">
<xsl:with-param name="tags" select="." />
<xsl:with-param name="datatypes" select="$datatypes" />
</xsl:call-template>
</xsl:copy>
</xsl:when>
<!--Otherwise, sort members in the same order as datatype-->
<xsl:otherwise>
<!--Build variable with sorted members.-->
<xsl:variable name="tag-members-sorted">
<xsl:for-each select="*">
<xsl:sort data-type="number" order="ascending" select="string-length(substring-before($tokens, concat(' | ', #Name)))" /> <!--Magic Sort Algorithm-->-->
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<!--Copy the parent node node.-->
<xsl:copy>
<xsl:copy-of select="#*"/>
<!--Now sort and copy the children.-->
<xsl:for-each select="msxsl:node-set($tag-members-sorted)/*">
<!--Recurse. This copies the child node.-->
<xsl:call-template name="sort-by-datatype">
<xsl:with-param name="tags" select="." />
<xsl:with-param name="datatypes" select="$datatypes" />
</xsl:call-template>
</xsl:for-each>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!--Pack tags-->
<xsl:variable name="tags-packed">
<xsl:call-template name="sort-by-datatype">
<xsl:with-param name="tags" select="/Program/Tags/Tag" />
<xsl:with-param name="datatypes" select="$datatypes-packed" />
</xsl:call-template>
</xsl:variable>
<!--Skipped for brevity-->
</xsl:stylesheet>

Split variables separated by a comma, and perform an action on each

I am using XSLT v1.0 and running it through Microsoft Visual Studio.
I have data (which will be different in every node) but is structured like this:
<ItemGroupData ItemGroupOID="DDG4">
<ItemDataString ItemOID="DDLOCC" AuditRecordID="AR.8452551">5,8,9,2,3</ItemDataString>
<ItemDataString ItemOID="DDLOCL" AuditRecordID="AR.8452551">1,7</ItemDataString>
<ItemDataString ItemOID="DDLOCR" AuditRecordID="AR.8452551">1</ItemDataString>
</ItemGroupData>
There can be any number of values separated by commas in each of the 3 fields.
I am trying to split the data so I can work with each individual integer, and have tried the method suggested by Dimitre Novatchev here: split function in xslt 1.0, but it keeps giving me the error:
"'template' is not a recognized extension element. An error occurred at (0,0).".
The new split/mark templates I created are inside my overall template, which is being used to convert my XML to a CSV file.
Can I have a template within a template? Or do I need to define it outside the main template? Bit of a N00b with XML so any help would be greatly appreciated.
My new templates (note the processedItem bit has been simplified for demonstration purposes):
<xsl:template match="mark">
<xsl:variable name="vrtfSplit">
<xsl:apply-templates/>
</xsl:variable>
<xsl:for-each select="ext:node-set($vrtfSplit)/*">
<processedItem>
<xsl:if test="$varLOCOID='DDLOCL'">
<xsl:value-of select="current() * 100"/>
</xsl:if>
<xsl:if test="$varLOCOID='DDLOCC'">
<xsl:value-of select="current() * 10"/>
</xsl:if>
<xsl:if test="$varLOCOID='DDLOCR'">
<xsl:value-of select="current() * 150"/>
</xsl:if>
</processedItem>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()" name="split">
<xsl:param name="pText" select="."/>
<xsl:if test="string-length($pText) > 0">
<item>
<xsl:value-of select="substring-before(concat($pText, ','), ',')"/>
</item>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring-after($pText, ',')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Consider the following example:
XSLT 1.0
<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="/ItemGroupData">
<output>
<xsl:apply-templates/>
</output>
</xsl:template>
<xsl:template match="ItemDataString">
<items>
<xsl:call-template name="tokenize-and-process">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="factor">
<xsl:choose>
<xsl:when test="#ItemOID='DDLOCL'">100</xsl:when>
<xsl:when test="#ItemOID='DDLOCC'">10</xsl:when>
<xsl:when test="#ItemOID='DDLOCR'">150</xsl:when>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</items>
</xsl:template>
<xsl:template name="tokenize-and-process">
<xsl:param name="text"/>
<xsl:param name="factor" select="1"/>
<xsl:param name="delimiter" select="','"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
<item>
<xsl:value-of select="$token * $factor"/>
</item>
<xsl:if test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="tokenize-and-process">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
<xsl:with-param name="factor" select="$factor"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Applied to your example input XML, the result will be:
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>
<items>
<item>50</item>
<item>80</item>
<item>90</item>
<item>20</item>
<item>30</item>
</items>
<items>
<item>100</item>
<item>700</item>
</items>
<items>
<item>150</item>
</items>
</output>
P.S. No, a template cannot be a child of another template.

Sort and concatenate consecutive nodes

I have a XML file which looks roughly like this (actual file is much more complex, everything has been truncated in this example):
<?xml version="1.0" encoding="utf-8"?>
<root>
<element>
<tag1>1</tag1>
<tag2>stuff</tag2>
<type>String</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>2</tag1>
<tag2>stuff</tag2>
<type>String</type>
<type>Date</type>
<type>Float</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>3</tag1>
<tag2>stuff</tag2>
<type>DateTime</type>
<tag3>stuff</tag3>
</element>
<element>
<tag1>4</tag1>
<tag2>stuff</tag2>
<type>Float</type>
<type>String</type>
<type>Date</type>
<tag3>stuff</tag3>
</element>
</root>
I process it with the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type"><xsl:call-template name="type"/></xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="type">
<xsl:variable name="initialType" select="translate(type,' ','')"/>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
And I get this resulting file:
<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:float"/>
My problem here is that only the first <type> tag is taken into account. What I would like is to concatenate all the type tag contents into the type tag of the output, preceded by a sign indicating that the tag is an agglomerate if applicable.
However, to avoid creating artificially numerous types, the content of the tags must be alphabetically sorted first. In this example, the <element> number 2 and 4 are both made of only Float, String, and Date, albeit in a different order. They need to have the same type in the output.
The following output would be acceptable:
<?xml version="1.0" encoding="UTF-8"?>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>
I am very new to XLST, and I have not managed to get anywhere close to the desired output so far. The code I have tried is just below, and fails horribly, notably because I failed to understand how to get <xsl:sort> working:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type">
<xsl:apply-templates>
<xsl:sort select="."/>
</xsl:apply-templates>
<xsl:call-template name="type"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="type">
<xsl:choose>
<xsl:when test="following-sibling::type">
<xs:text>union</xs:text>
<xsl:for-each select="following-sibling::type">
<xs:text>translate(type,' ','')</xs:text>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="initialType" select="translate(type,' ','')"/>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Just a few adjustments on your existing code were needed.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type">
<xsl:variable name="sorted">
<xsl:for-each select="type">
<xsl:sort select="."/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:apply-templates select="$sorted/type"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="type">
<xsl:variable name="initialType" select="translate(., ' ', '')"/>
<xsl:if test="count(preceding-sibling::type) = 0 and count(following-sibling::type) > 0">
<xsl:text>union</xsl:text>
</xsl:if>
<!-- HINT remove if you dont want any seperator -->
<xsl:if test="count(preceding-sibling::type) > 0">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:choose>
<xsl:when test="$initialType='String'">
<xsl:text>xs:string</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Date'">
<xsl:text>xs:date</xsl:text>
</xsl:when>
<xsl:when test="$initialType='DateTime'">
<xsl:text>xs:dateTime</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Float'">
<xsl:text>xs:float</xsl:text>
</xsl:when>
<xsl:when test="$initialType='Integer'">
<xsl:text>xs:int</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$initialType"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Please verify, for me i get the output (see HINT inline in XSLT):
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:date xs:float xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:date xs:float xs:string"/>
I would do it like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="element">
<xsl:element name="xs:element">
<xsl:attribute name="type">
<xsl:apply-templates select="type">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'String']">xs:string</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'Date']">xs:date</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'DateTime']">xs:dateTime</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'Float']">xs:float</xsl:template>
<xsl:template match="type[translate(., ' ', '') = 'Integer']">xs:int</xsl:template>
<xsl:template match="type">
<xsl:value-of select="translate(., ' ', '')"/>
</xsl:template>
</xsl:stylesheet>

Sales Order Taxes For Dynamics GP

In Microsoft Dynamics GP I need to set the tax on individual orders as taxable/non-taxable (cannot be done on customer record).
For some reason no matter what I pass into the CreateSalesOrder call for the web services, it will not save the tax information.
I've tried:
Using the CreateSalesInvoice policy which has had "Create Taxes Behavior" set to "Taxes will be provided"
Overrode policies using "Use Header Level Taxes Behavior" and "Create Taxes Behavior" all 4 modes have been tried.
Provided taxes as a total on the Sales Order
Provided taxes as a tax detail on the sales order
Provided taxes as a total on the line item
Provided taxes as a tax detail on the sales order
Set the TaxScheduleKey on the order
Set the TaxScheduleKey on the line items
Taxes just get blanked out in GP, it's infuriating... Any ideas? I do have access to the Dynamics database but I'd really rather not go that route if possible.
My research has led me to believe that this is broken (every thread on this subject ends with no answers) and Microsoft isn't going to fix it, but that really hurts automation something awful.
Ran into this issue today. A little background:
After trying everything outlined above, modifying policies - particularly, Sales Document - Create Sales Document policies, and becoming frustrated at there being no policies for Create Sales Order to allow taxes to be specified, I came across this MSDN article about how the GP Services could be designed or extended: https://msdn.microsoft.com/en-us/library/dd996499.aspx
Not interested in going quite that far, I found - "Program Files\Microsoft Dynamics\GPWebServices\XSLT", in particular, the "Microsoft.Dynamics.GP.SalesOrderCreate.xslt" file.
As it comes installed with GreatPlains, there are no transforms in place to utilize incoming tax data at all (no surprise, given what had been tried). USINGHEADERLEVELTAXES is set to 0.
Combining the Tax lines from the "Microsoft.Dynamics.GP.SalesInvoiceCreate.xslt" file into the SalesOrderCreate.xslt file, you can modify the XML sent into eConnect for SalesOrderCreate to properly create the Taxes.
The below example uses/was tested for header level tax behavior.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mbs="http://schemas.microsoft.com/dynamics/2006/01"
xmlns:gputil="urn:Microsoft.Dynamics.GP.TransformUtilities"
version="1.0">
<xsl:import href="Microsoft.Dynamics.GP.SalesCreateUpdateLibrary.xslt"/>
<xsl:import href="Microsoft.Dynamics.GP.StandardLibrary.xslt"/>
<xsl:variable name="CompanyId">
<xsl:value-of select="/SalesOrder/mbs:Context/mbs:OrganizationKey/mbs:Id"/>
</xsl:variable>
<xsl:template match ="/">
<eConnect xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:apply-templates />
</eConnect>
</xsl:template>
<xsl:template match="SalesOrder">
<SOPTransactionType>
<xsl:apply-templates select="Lines/SalesOrderLine/Serials/SalesLineSerial">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="Lines/SalesOrderLine/Components/SalesOrderComponent/Serials/SalesComponentSerial">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="Lines/SalesOrderLine/Lots/SalesLineLot">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="Lines/SalesOrderLine/Components/SalesOrderComponent/Lots/SalesComponentLot">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="Lines/SalesOrderLine" />
<xsl:apply-templates select="Lines/SalesOrderLine/Components/SalesOrderComponent" />
<xsl:apply-templates select="TrackingNumbers/SalesTrackingNumber" />
<xsl:apply-templates select="Taxes/SalesDocumentTax" />
<xsl:apply-templates select="Commissions/SalesCommission" />
<xsl:apply-templates select="Payments/SalesPayment">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="UserDefined" />
<xsl:apply-templates select="Lines/SalesOrderLine/Bins/SalesLineBin" />
<xsl:apply-templates select="Lines/SalesOrderLine/Components/SalesOrderComponent/Bins/SalesComponentBin" />
<xsl:call-template name="SalesHeader" />
<xsl:apply-templates select="ProcessHolds/SalesProcessHold">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
</xsl:apply-templates>
</SOPTransactionType>
</xsl:template>
<xsl:template match="SalesOrderLine">
<taSopLineIvcInsert>
<xsl:call-template name="CreateUpdateLine">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
<xsl:with-param name="CompanyId">
<xsl:value-of select="$CompanyId" />
</xsl:with-param>
</xsl:call-template>
<xsl:if test="QuantityToBackorder/Value != ''">
<QTYTBAOR>
<xsl:value-of select="QuantityToBackorder/Value" />
</QTYTBAOR>
</xsl:if>
<xsl:if test="QuantityToInvoice/Value != ''">
<QUANTITY>
<xsl:value-of select="QuantityToInvoice/Value" />
</QUANTITY>
</xsl:if>
<xsl:if test="QuantityCanceled/Value != ''">
<QTYCANCE>
<xsl:value-of select="QuantityCanceled/Value" />
</QTYCANCE>
</xsl:if>
<xsl:if test="QuantityFulfilled/Value != ''">
<QTYFULFI>
<xsl:value-of select="QuantityFulfilled/Value" />
</QTYFULFI>
</xsl:if>
<xsl:if test="TaxAmount/Value != ''">
<TAXAMNT>
<xsl:value-of select="TaxAmount/Value" />
</TAXAMNT>
</xsl:if>
<RecreateDist>0</RecreateDist>
</taSopLineIvcInsert>
</xsl:template>
<xsl:template match="SalesOrderComponent">
<taSopLineIvcInsertComponent>
<xsl:call-template name="CreateUpdateComponent">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
</xsl:call-template>
<xsl:if test="QuantityToBackorder/Value != ''">
<QTYTBAOR>
<xsl:value-of select="QuantityToBackorder/Value" />
</QTYTBAOR>
</xsl:if>
<xsl:if test="QuantityToInvoice/Value != ''">
<QUANTITY>
<xsl:value-of select="QuantityToInvoice/Value" />
</QUANTITY>
</xsl:if>
<xsl:if test="QuantityCanceled/Value != ''">
<QTYCANCE>
<xsl:value-of select="QuantityCanceled/Value" />
</QTYCANCE>
</xsl:if>
<xsl:if test="QuantityFulfilled/Value != ''">
<QTYFULFI>
<xsl:value-of select="QuantityFulfilled/Value" />
</QTYFULFI>
</xsl:if>
</taSopLineIvcInsertComponent>
</xsl:template>
<xsl:template name="SalesHeader">
<taSopHdrIvcInsert>
<xsl:call-template name="CreateUpdateDocument">
<xsl:with-param name="UpdateIfExists">0</xsl:with-param>
<xsl:with-param name="CompanyId">
<xsl:value-of select="$CompanyId" />
</xsl:with-param>
</xsl:call-template>
<xsl:if test="PaymentAmount/Value != ''">
<PYMTRCVD>
<xsl:value-of select="PaymentAmount/Value" />
</PYMTRCVD>
</xsl:if>
<xsl:if test="TaxAmount/Value != ''">
<TAXAMNT>
<xsl:value-of select="TaxAmount/Value" />
</TAXAMNT>
</xsl:if>
<USINGHEADERLEVELTAXES>1</USINGHEADERLEVELTAXES>
<CREATEDIST>0</CREATEDIST>
<CREATETAXES>0</CREATETAXES>
</taSopHdrIvcInsert>
</xsl:template>
</xsl:stylesheet>

SharePoint 2013 Blog: sort posts by authors

I'm trying to make a custom filter which sorts on authors (users) in the SharePoint 2013 blog. I'm working with XSL dataview and it's exported to a web part. I have a column called Author which gets the information from Created By. When I click on a user in the web part it shows all posts instead of the selected author. The URL is mysite/default.aspx?Author=FirstName LastName".
Code (default.aspx):
<xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
<xsl:call-template name="dvt_1"/>
</xsl:template>
<xsl:template name="dvt_1">
<xsl:variable name="dvt_StyleName">RepForm3</xsl:variable>
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row[not(#Author.title=preceding-sibling::Row/#Author.title)]" />
<xsl:call-template name="dvt_1.header">
<xsl:with-param name="Rows" select="$Rows" />
</xsl:call-template>
<div class="blogRefineByAuthorContainer">
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows"/>
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="dvt_1.header">
<xsl:param name="Rows" />
<div class="blogRefineByAuthorEveryAuthor">Everyone</div>
</xsl:template>
<xsl:template name="dvt_1.body">
<xsl:param name="Rows"/>
<xsl:for-each select="$Rows">
<xsl:call-template name="dvt_1.rowview" />
</xsl:for-each>
</xsl:template>
<xsl:template name="dvt_1.rowview">
<div class="blogRefineByAuthorAuthorTitle">
<xsl:value-of select="#Author.title" />
</div>
</xsl:template>
Any ideas of what it could be? Between the first and last name there is a space in the URL, but I don't think it makes any sense. I have tried with %20 without any result.

Resources