不同名称空间中相似元素的高效映射 (XSLT 1.0)
Efficient mapping of alike elements in different namespaces (XSLT 1.0)
我需要翻译 XML->XML 多个输入文档,这些文档“嵌入”了具有不同命名空间的文档。这些嵌入式文档具有相同类型的元素(即基于相同的 xsd),我想以通用方式/模板将其映射到输出文档中 - 无论命名空间如何。
简单示例输入XML:
<?xml version="1.0" encoding="UTF-8"?>
<Message xmnls="mymessage">
<Header>...</Header>
<Body xmlns="type1">
<DocumentType1>
<Creditor>
<Name>Mr Creditor</Name>
<Address>Muddy Creek 42</Address>
</Creditor>
<CreditorAccount>
<Id>794115296</Id>
</CreditorAccount>
</DocumentType1>
</Body>
</Message>
示例输入 XML 2:
<?xml version="1.0" encoding="UTF-8"?>
<Message xmnls="mymessage">
<Header>...</Header>
<Body xmlns="type2"><!-- different namespace -->
<DocumentType2>
<Creditor><!-- same element -->
<Name>Mr Creditor</Name>
<Address>Muddy Creek 42</Address>
</Creditor>
<CreditorAccount>
<Id>794115296</Id>
</CreditorAccount>
</DocumentType2>
</Body>
</Message>
对于这两个示例,我想提取结构相同的“债权人”信息。
但正如您所见,正文命名空间(“type1”、“type2”...)和子元素名称(“DocumentType1”,...)各不相同,即整个名称,而不仅仅是末尾的数字。
两种情况下的输出应该是这样的:
<?xml version="1.0"?>
<Request>
<Creditor>
<Name>Mr Creditor</Name>
<Address>Muddy Creek 42</Address>
<Account>794115296</Account>
</Creditor>
</Request>
我如何才能以 XSLT 1.0/libxml+exslt 的最佳方式映射输出格式中两个消息示例的贷方信息?遗憾的是我绑定了1.0.
我当然可以使用“通配符”,但我担心这会降低性能。 XSLT 中将有很多这样的映射,并且输入数据比示例更多。你有关于性能的经验吗?
否则我需要为每个不同的命名空间创建一个模板,对吗?据我了解,无法在 XSLT 中动态设置名称空间的别名。
这是一个使用 'wildcards' 的 XSLT 示例:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mymessage="urn:mymessage"
exclude-result-prefixes="xsi xsl mymessage"
version="1.0">
<xsl:template match="//mymessage:Message">
<Request>
<xsl:apply-templates/>
</Request>
</xsl:template>
<xsl:template match="mymessage:Header"/>
<xsl:template match="*[local-name()='Body']">
<Creditor>
<Name>
<xsl:value-of select="*/*[local-name()='Creditor']/*[local-name()='Name']"/>
</Name>
<Address>
<xsl:value-of select="*/*[local-name()='Creditor']/*[local-name()='Address']"/>
</Address>
<Account>
<xsl:value-of select="*/*[local-name()='CreditorAccount']/*[local-name()='Id']"/>
</Account>
</Creditor>
</xsl:template>
</xsl:stylesheet>
感谢您的帮助! :)
无法评论 libxslt 性能 - 但您尝试过吗?编写可读和可维护的代码,并且只有在给您带来可衡量的性能问题时才更改它。
当您想要处理多个命名空间中的输入时,另一种方法是进行两次传递:第一次传递去除(或规范化)命名空间,然后第二次传递处理统一命名空间中的元素。对于第一遍,只需使用 <xsl:element name="{local-name()}">
显然,XSLT 2.0+ 为您提供了部分通配符语法 *:local
,这使得此类代码更具可读性。
我需要翻译 XML->XML 多个输入文档,这些文档“嵌入”了具有不同命名空间的文档。这些嵌入式文档具有相同类型的元素(即基于相同的 xsd),我想以通用方式/模板将其映射到输出文档中 - 无论命名空间如何。
简单示例输入XML:
<?xml version="1.0" encoding="UTF-8"?>
<Message xmnls="mymessage">
<Header>...</Header>
<Body xmlns="type1">
<DocumentType1>
<Creditor>
<Name>Mr Creditor</Name>
<Address>Muddy Creek 42</Address>
</Creditor>
<CreditorAccount>
<Id>794115296</Id>
</CreditorAccount>
</DocumentType1>
</Body>
</Message>
示例输入 XML 2:
<?xml version="1.0" encoding="UTF-8"?>
<Message xmnls="mymessage">
<Header>...</Header>
<Body xmlns="type2"><!-- different namespace -->
<DocumentType2>
<Creditor><!-- same element -->
<Name>Mr Creditor</Name>
<Address>Muddy Creek 42</Address>
</Creditor>
<CreditorAccount>
<Id>794115296</Id>
</CreditorAccount>
</DocumentType2>
</Body>
</Message>
对于这两个示例,我想提取结构相同的“债权人”信息。 但正如您所见,正文命名空间(“type1”、“type2”...)和子元素名称(“DocumentType1”,...)各不相同,即整个名称,而不仅仅是末尾的数字。
两种情况下的输出应该是这样的:
<?xml version="1.0"?>
<Request>
<Creditor>
<Name>Mr Creditor</Name>
<Address>Muddy Creek 42</Address>
<Account>794115296</Account>
</Creditor>
</Request>
我如何才能以 XSLT 1.0/libxml+exslt 的最佳方式映射输出格式中两个消息示例的贷方信息?遗憾的是我绑定了1.0.
我当然可以使用“通配符”,但我担心这会降低性能。 XSLT 中将有很多这样的映射,并且输入数据比示例更多。你有关于性能的经验吗?
否则我需要为每个不同的命名空间创建一个模板,对吗?据我了解,无法在 XSLT 中动态设置名称空间的别名。
这是一个使用 'wildcards' 的 XSLT 示例:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mymessage="urn:mymessage"
exclude-result-prefixes="xsi xsl mymessage"
version="1.0">
<xsl:template match="//mymessage:Message">
<Request>
<xsl:apply-templates/>
</Request>
</xsl:template>
<xsl:template match="mymessage:Header"/>
<xsl:template match="*[local-name()='Body']">
<Creditor>
<Name>
<xsl:value-of select="*/*[local-name()='Creditor']/*[local-name()='Name']"/>
</Name>
<Address>
<xsl:value-of select="*/*[local-name()='Creditor']/*[local-name()='Address']"/>
</Address>
<Account>
<xsl:value-of select="*/*[local-name()='CreditorAccount']/*[local-name()='Id']"/>
</Account>
</Creditor>
</xsl:template>
</xsl:stylesheet>
感谢您的帮助! :)
无法评论 libxslt 性能 - 但您尝试过吗?编写可读和可维护的代码,并且只有在给您带来可衡量的性能问题时才更改它。
当您想要处理多个命名空间中的输入时,另一种方法是进行两次传递:第一次传递去除(或规范化)命名空间,然后第二次传递处理统一命名空间中的元素。对于第一遍,只需使用 <xsl:element name="{local-name()}">
显然,XSLT 2.0+ 为您提供了部分通配符语法 *:local
,这使得此类代码更具可读性。