处理XSLT中的特殊字符以获得格式良好的输出XML
我需要将下面的输入XML转换为所需的输出XML格式。在这个论坛的帮助下,我得到了如下解决方案: 输入XML处理XSLT中的特殊字符以获得格式良好的输出XML,xml,xslt,special-characters,Xml,Xslt,Special Characters,我需要将下面的输入XML转换为所需的输出XML格式。在这个论坛的帮助下,我得到了如下解决方案: 输入XML <?xml version="1.0"?> <dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"> <metadata> <item name="Employ
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="Employee Id" />
<item name="Employee Name" />
<item name="Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
<?xml version="1.0" encoding="UTF-16"?>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
<Employee_Id>1</Employee_Id>
<Employee_Name Salutation="Dr.">John</Employee_Name>
<Department_Name>Finance</Department_Name>
</row>
<row>
<Employee_Id>2</Employee_Id>
<Employee_Name Salutation="Mr.">Peter</Employee_Name>
<Department_Name>Admin</Department_Name>
</row>
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="1Employee Id" />
<item name=" Employee Name" />
<item name="$Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
1.
约翰
财务
2.
彼得
管理
XSLT转换
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:c="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames" select="/*/c:metadata/*/@name" />
<xsl:template match="/*/c:data">
<dataset>
<xsl:apply-templates/>
</dataset>
</xsl:template>
<xsl:template match="c:row">
<row>
<xsl:apply-templates/>
</row>
</xsl:template>
<xsl:template match="c:row/*">
<xsl:variable name="vPos" select="position()"/>
<xsl:element name="{translate($vNames[$vPos], ' ', '_')}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
所需的输出XML
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="Employee Id" />
<item name="Employee Name" />
<item name="Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
<?xml version="1.0" encoding="UTF-16"?>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
<Employee_Id>1</Employee_Id>
<Employee_Name Salutation="Dr.">John</Employee_Name>
<Department_Name>Finance</Department_Name>
</row>
<row>
<Employee_Id>2</Employee_Id>
<Employee_Name Salutation="Mr.">Peter</Employee_Name>
<Department_Name>Admin</Department_Name>
</row>
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="1Employee Id" />
<item name=" Employee Name" />
<item name="$Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
1.
约翰
财务
2.
彼得
管理
然而,我遇到了一个特殊的场景,打破了这个解决方案。输入XML中的属性值可以以数字、特殊字符或空格开头
新输入XML
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="Employee Id" />
<item name="Employee Name" />
<item name="Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
<?xml version="1.0" encoding="UTF-16"?>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
<Employee_Id>1</Employee_Id>
<Employee_Name Salutation="Dr.">John</Employee_Name>
<Department_Name>Finance</Department_Name>
</row>
<row>
<Employee_Id>2</Employee_Id>
<Employee_Name Salutation="Mr.">Peter</Employee_Name>
<Department_Name>Admin</Department_Name>
</row>
<?xml version="1.0"?>
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="1Employee Id" />
<item name=" Employee Name" />
<item name="$Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
1.
约翰
财务
2.
彼得
管理
由于name属性值被转换为元素名称,上述转换失败,因为元素名称不能以数字或空格开头。
在本例中,我想用元素名的一些有效字符替换这些字符,比如\uu
或C\u
,以获得相同的所需输出XML
请让我知道如何处理这种情况
任何帮助都将不胜感激
提前谢谢
这很容易。只需扩展translate()调用的范围以涵盖问题字符(您在属性中使用的字符,但XML禁止用于元素名称) 例如,改变
<xsl:element name="{translate($vNames[$vPos], ' ', '_')}">
……或者
<xsl:element name="{translate( substring( $vName, 1, 1), '$', '_')}{substring( $vName, 2)}" />
注
如果您能够升级到XSLT2.0,那么使用正则表达式将变得更容易
<xsl:element name="{replace( $vName, '^[$]', '_')}" />
这是一个完整的解决方案,它不使用任何硬编码特殊字符:
<xsl:stylesheet version="1.0"
xmlns:c="http://developer.cognos.com/schemas/xmldata/1/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames" select="/*/c:metadata/*/@name" />
<xsl:variable name="vAlpha" select=
"concat('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')"/>
<xsl:template match="/*/c:data">
<dataset>
<xsl:apply-templates/>
</dataset>
</xsl:template>
<xsl:template match="c:row">
<row>
<xsl:apply-templates/>
</row>
</xsl:template>
<xsl:template match="c:row/*">
<xsl:variable name="vPos" select="position()"/>
<xsl:variable name="vChar1" select=
"translate(substring($vNames[$vPos],1,1),
translate(substring($vNames[$vPos],1,1), $vAlpha, ''),
'_')"/>
<xsl:element name=
"{$vChar1}{translate(substring($vNames[$vPos],2), ' ', '_')}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
<_Employee_Id>1</_Employee_Id>
<_Employee_Name Salutation="Dr.">John</_Employee_Name>
<_Department_Name>Finance</_Department_Name>
</row>
<row>
<_Employee_Id>2</_Employee_Id>
<_Employee_Name Salutation="Mr.">Peter</_Employee_Name>
<_Department_Name>Admin</_Department_Name>
</row>
</dataset>
在提供的XML文档上应用此转换时:
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<metadata>
<item name="1Employee Id" />
<item name=" Employee Name" />
<item name="$Department Name" />
</metadata>
<data>
<row>
<value>1</value>
<value Salutation="Dr." >John</value>
<value>Finance</value>
</row>
<row>
<value>2</value>
<value Salutation="Mr." >Peter</value>
<value>Admin</value>
</row>
</data>
</dataset>
1.
约翰
财务
2.
彼得
管理
生成所需的正确结果:
<xsl:stylesheet version="1.0"
xmlns:c="http://developer.cognos.com/schemas/xmldata/1/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames" select="/*/c:metadata/*/@name" />
<xsl:variable name="vAlpha" select=
"concat('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')"/>
<xsl:template match="/*/c:data">
<dataset>
<xsl:apply-templates/>
</dataset>
</xsl:template>
<xsl:template match="c:row">
<row>
<xsl:apply-templates/>
</row>
</xsl:template>
<xsl:template match="c:row/*">
<xsl:variable name="vPos" select="position()"/>
<xsl:variable name="vChar1" select=
"translate(substring($vNames[$vPos],1,1),
translate(substring($vNames[$vPos],1,1), $vAlpha, ''),
'_')"/>
<xsl:element name=
"{$vChar1}{translate(substring($vNames[$vPos],2), ' ', '_')}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
<_Employee_Id>1</_Employee_Id>
<_Employee_Name Salutation="Dr.">John</_Employee_Name>
<_Department_Name>Finance</_Department_Name>
</row>
<row>
<_Employee_Id>2</_Employee_Id>
<_Employee_Name Salutation="Mr.">Peter</_Employee_Name>
<_Department_Name>Admin</_Department_Name>
</row>
</dataset>
1.
约翰
财务
2.
彼得
管理
说明:
<xsl:stylesheet version="1.0"
xmlns:c="http://developer.cognos.com/schemas/xmldata/1/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames" select="/*/c:metadata/*/@name" />
<xsl:variable name="vAlpha" select=
"concat('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')"/>
<xsl:template match="/*/c:data">
<dataset>
<xsl:apply-templates/>
</dataset>
</xsl:template>
<xsl:template match="c:row">
<row>
<xsl:apply-templates/>
</row>
</xsl:template>
<xsl:template match="c:row/*">
<xsl:variable name="vPos" select="position()"/>
<xsl:variable name="vChar1" select=
"translate(substring($vNames[$vPos],1,1),
translate(substring($vNames[$vPos],1,1), $vAlpha, ''),
'_')"/>
<xsl:element name=
"{$vChar1}{translate(substring($vNames[$vPos],2), ' ', '_')}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
<dataset xmlns:c="http://developer.cognos.com/schemas/xmldata/1/">
<row>
<_Employee_Id>1</_Employee_Id>
<_Employee_Name Salutation="Dr.">John</_Employee_Name>
<_Department_Name>Finance</_Department_Name>
</row>
<row>
<_Employee_Id>2</_Employee_Id>
<_Employee_Name Salutation="Mr.">Peter</_Employee_Name>
<_Department_Name>Admin</_Department_Name>
</row>
</dataset>
属性值中是否包含数字或特殊字符,还是仅在开头?对于数字,如果属性值以数字结尾,您是否仍希望它出现在输出的元素名称中?如果您不能确定列名是否为有效的XML名称,则选择像
value
这样的输出格式比选择value
更安全。对于长列名,这可能不会太冗长,因为在开始和结束标记中都没有重复名称。@IanRoberts,谢谢你的建议。输出XML必须由另一个应用程序使用,该应用程序希望它采用这种格式。非常好的解决方案Sean,我想不出来+1@Sean,谢谢你的回复。我的错误是,我解释问题时不够清楚。我不想替换完整字符串中的字符。我只想替换第一个字符,如果它是非法字符,以确保输出的XML是格式良好的XML。+1用于使用双翻译;在这些类型的“白名单”场景中更易于维护。@DimitreNovatchev,再次感谢您的回复。它工作得非常好。基于您的解决方案和一些更可能的方案,我提出了解决方案,我将在下面发布。@DimitreNovatchev,我遇到了另一种特殊情况,传入的XML在value元素code
P&Gcode
中包含无效字符。我能想到的一个解决方案是使用CDATA将所有值包装到输出xml中,但在XSLT中无法实现。如果我用CDATA包装的方法有误,请告诉我好吗?如果没有,那么如何实现它。谢谢