在仅命名空间不同的两个模式之间转换 XML 文档
Transforming XML document between two schemas differing only in namespaces
如果我对问题的描述不清楚或过于复杂,我提前表示歉意。我只是想确保我包含了问题的所有方面。
我有一个场景,我收到 XML 个对模式有效的文档,我们称之为 S1,看起来像这样(简化):
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
targetNamespace="http://somename.org/original"
xmlns="http://somename.org/original"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:imported="http://somename.org/originalimported"
elementFormDefault="unqualified">
<xs:import namespace="http://somename.org/originalimported"/>
<xs:element name="someElement">
<xs:complexType>
<xs:sequence>
<xs:element ref="imported:someelement" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
如您所见,它导入了另一个名称空间,看起来像这样(也经过简化)并从中引用了一个元素:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="http://somename.org/originalimported"
xmlns="http://somename.org/originalimported"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0"
elementFormDefault="unqualified">
<xs:element name="someelement">
<xs:complexType>
...
</xs:complexType>
</xs:element>
</xs:schema>
我还有另外两个模式 "mirroring" 以上两个,唯一的区别是名称空间“http://somename.org/original" is replaced with "http://somename.org/new" and the namespace "http://somename.org/originalimported" is replaced with "http://somename.org/newimported”。除此之外完全相同。看起来像这样(我们称之为 S2):
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
targetNamespace="http://somename.org/new"
xmlns="http://somename.org/new"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:imported="http://somename.org/newimported"
elementFormDefault="unqualified">
<xs:import namespace="http://somename.org/newimported"/>
<xs:element name="someElement">
<xs:complexType>
<xs:sequence>
<xs:element ref="imported:someelement" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
...以及导入的:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="http://somename.org/newimported"
xmlns="http://somename.org/newimported"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0"
elementFormDefault="unqualified">
<xs:element name="someelement">
<xs:complexType>
...
</xs:complexType>
</xs:element>
</xs:schema>
我需要做的是转换 任何 我收到的针对 S1 验证的文档并将其转换为针对 S2 进行验证。最可靠和最快的方法是什么?我意识到一种方法是在 XML 文档中简单地使用字符串替换来替换实际的命名空间,但是如果文档很大,这似乎不是最有效的方法。
实际转换必须使用 C# 中可用的方法完成(包括 XML/schema/XSLT 类)。
提前致谢!
您可以使用类似
的方法
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:input1="http://example.com/original"
xmlns:input2="http://example.com/originalimported"
exclude-result-prefixes="input1 input2">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="input1:*">
<xsl:element name="{name()}" namespace="http://example.com/new">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="input2:*">
<xsl:element name="{name()}" namespace="http://example.com/newimported">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
但我想看一些示例文档来拼写并测试它。特别是 elementFormDefault="unqualified"
可能意味着里面的其他元素不在任何命名空间中,上面的内容会将它们与范围内父级的命名空间一起复制,这可能不是您想要的,所以也许做
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:input1="http://example.com/original"
xmlns:input2="http://example.com/originalimported"
exclude-result-prefixes="input1 input2">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="input1:*">
<xsl:element name="{name()}" namespace="http://example.com/new">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="input2:*">
<xsl:element name="{name()}" namespace="http://example.com/newimported">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
更好。
至于提供名称空间作为参数,我建议采用以下方法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:param name="input-ns1" select="'http://example.com/original'"/>
<xsl:param name="output-ns1" select="'http://example.com/new'"/>
<xsl:param name="input-ns2" select="'http://example.com/originalimported'"/>
<xsl:param name="output-ns2" select="'http://example.com/newimported'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[namespace-uri() = $input-ns1]">
<xsl:element name="{name()}" namespace="{$output-ns1}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[namespace-uri() = $input-ns2]">
<xsl:element name="{name()}" namespace="{$output-ns2}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
但我忘记了在 XSLT 1.0 中不允许匹配模式使用变量引用,因此该方法只有在您使用 XSLT 2.0 处理器(如 Saxon 9 或 XmlPrime)时才有效。
如果我对问题的描述不清楚或过于复杂,我提前表示歉意。我只是想确保我包含了问题的所有方面。
我有一个场景,我收到 XML 个对模式有效的文档,我们称之为 S1,看起来像这样(简化):
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
targetNamespace="http://somename.org/original"
xmlns="http://somename.org/original"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:imported="http://somename.org/originalimported"
elementFormDefault="unqualified">
<xs:import namespace="http://somename.org/originalimported"/>
<xs:element name="someElement">
<xs:complexType>
<xs:sequence>
<xs:element ref="imported:someelement" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
如您所见,它导入了另一个名称空间,看起来像这样(也经过简化)并从中引用了一个元素:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="http://somename.org/originalimported"
xmlns="http://somename.org/originalimported"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0"
elementFormDefault="unqualified">
<xs:element name="someelement">
<xs:complexType>
...
</xs:complexType>
</xs:element>
</xs:schema>
我还有另外两个模式 "mirroring" 以上两个,唯一的区别是名称空间“http://somename.org/original" is replaced with "http://somename.org/new" and the namespace "http://somename.org/originalimported" is replaced with "http://somename.org/newimported”。除此之外完全相同。看起来像这样(我们称之为 S2):
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
targetNamespace="http://somename.org/new"
xmlns="http://somename.org/new"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:imported="http://somename.org/newimported"
elementFormDefault="unqualified">
<xs:import namespace="http://somename.org/newimported"/>
<xs:element name="someElement">
<xs:complexType>
<xs:sequence>
<xs:element ref="imported:someelement" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
...以及导入的:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="http://somename.org/newimported"
xmlns="http://somename.org/newimported"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0"
elementFormDefault="unqualified">
<xs:element name="someelement">
<xs:complexType>
...
</xs:complexType>
</xs:element>
</xs:schema>
我需要做的是转换 任何 我收到的针对 S1 验证的文档并将其转换为针对 S2 进行验证。最可靠和最快的方法是什么?我意识到一种方法是在 XML 文档中简单地使用字符串替换来替换实际的命名空间,但是如果文档很大,这似乎不是最有效的方法。
实际转换必须使用 C# 中可用的方法完成(包括 XML/schema/XSLT 类)。
提前致谢!
您可以使用类似
的方法<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:input1="http://example.com/original"
xmlns:input2="http://example.com/originalimported"
exclude-result-prefixes="input1 input2">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="input1:*">
<xsl:element name="{name()}" namespace="http://example.com/new">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="input2:*">
<xsl:element name="{name()}" namespace="http://example.com/newimported">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
但我想看一些示例文档来拼写并测试它。特别是 elementFormDefault="unqualified"
可能意味着里面的其他元素不在任何命名空间中,上面的内容会将它们与范围内父级的命名空间一起复制,这可能不是您想要的,所以也许做
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:input1="http://example.com/original"
xmlns:input2="http://example.com/originalimported"
exclude-result-prefixes="input1 input2">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="input1:*">
<xsl:element name="{name()}" namespace="http://example.com/new">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="input2:*">
<xsl:element name="{name()}" namespace="http://example.com/newimported">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
更好。
至于提供名称空间作为参数,我建议采用以下方法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:param name="input-ns1" select="'http://example.com/original'"/>
<xsl:param name="output-ns1" select="'http://example.com/new'"/>
<xsl:param name="input-ns2" select="'http://example.com/originalimported'"/>
<xsl:param name="output-ns2" select="'http://example.com/newimported'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[namespace-uri() = $input-ns1]">
<xsl:element name="{name()}" namespace="{$output-ns1}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[namespace-uri() = $input-ns2]">
<xsl:element name="{name()}" namespace="{$output-ns2}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
但我忘记了在 XSLT 1.0 中不允许匹配模式使用变量引用,因此该方法只有在您使用 XSLT 2.0 处理器(如 Saxon 9 或 XmlPrime)时才有效。