Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
处理XSLT中的特殊字符以获得格式良好的输出XML_Xml_Xslt_Special Characters - Fatal编程技术网

处理XSLT中的特殊字符以获得格式良好的输出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转换为所需的输出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.
彼得
管理
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>
  • 我们可以使用双重翻译方法来识别不属于给定字符集的所有字符,Michael Kay首先展示了这种方法

  • 如果名称中除空格外还有其他非法字符,则可以使用相同的双翻译技术将任何此类(事先未知)字符替换为所需的合法字符


  • 属性值中是否包含数字或特殊字符,还是仅在开头?对于数字,如果属性值以数字结尾,您是否仍希望它出现在输出的元素名称中?如果您不能确定列名是否为有效的XML名称,则选择像
    value
    这样的输出格式比选择
    value
    更安全。对于长列名,这可能不会太冗长,因为在开始和结束标记中都没有重复名称。@IanRoberts,谢谢你的建议。输出XML必须由另一个应用程序使用,该应用程序希望它采用这种格式。非常好的解决方案Sean,我想不出来+1@Sean,谢谢你的回复。我的错误是,我解释问题时不够清楚。我不想替换完整字符串中的字符。我只想替换第一个字符,如果它是非法字符,以确保输出的XML是格式良好的XML。+1用于使用双翻译;在这些类型的“白名单”场景中更易于维护。@DimitreNovatchev,再次感谢您的回复。它工作得非常好。基于您的解决方案和一些更可能的方案,我提出了解决方案,我将在下面发布。@DimitreNovatchev,我遇到了另一种特殊情况,传入的XML在value元素
    code
    P&G
    code
    中包含无效字符。我能想到的一个解决方案是使用CDATA将所有值包装到输出xml中,但在XSLT中无法实现。如果我用CDATA包装的方法有误,请告诉我好吗?如果没有,那么如何实现它。谢谢