XSLT,动态设置命名空间并从输出xml

时间:2016-06-26 00:42:06

标签: xml xslt namespaces

我的源xml是:

<?xml version="1.0" encoding="UTF-8"?>
<PMML version="4.1" xmlns="http://www.dmg.org/PMML-4_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.dmg.org/PMML-4_1 pmml-4-1.xsd">
<Header copyright="(C) Copyright IBM Corp. 1989, 2014.">
    <Application name="IBM SPSS Statistics 23.0" version="23.0.0.0"/>
</Header>
<GeneralRegressionModel algorithmName="multinomialLogistic" functionName="classification" modelType="multinomialLogistic" targetVariableName="CLASS">
    <MiningSchema>
        <MiningField missingValueTreatment="asIs" name="CLASS" usageType="predicted"/>
        <MiningField missingValueTreatment="asIs" name="ACTIVE_CUSTOMER" usageType="active"/>
        <MiningField missingValueTreatment="asIs" name="SEGMENT" usageType="active"/>
    </MiningSchema>
    <ParameterList>
        <Parameter label="Konstanter Term" name="P0000001"/>
        <Parameter label="[ACTIVE_CUSTOMER=0]" name="P0000002"/>
        <Parameter label="[ACTIVE_CUSTOMER=1]" name="P0000003"/>
        <Parameter label="[SEGMENT=0]" name="P00000004"/>
        <Parameter label="[SEGMENT=1]" name="P00000005"/>
    </ParameterList>
    <ParamMatrix>
        <PCell beta="-167.307903919999" df="1" parameterName="P0000001" targetCategory="1"/>
        <PCell beta="-0.0747629275586869" df="1" parameterName="P0000002" targetCategory="1"/>
        <PCell beta="0.409965797830495" df="1" parameterName="P0000003" targetCategory="1"/>
        <PCell beta="-1.03190717557433" df="1" parameterName="P0000004" targetCategory="1"/>
        <PCell beta="0.904157514089376" df="1" parameterName="P0000005" targetCategory="1"/>
    </ParamMatrix>
</GeneralRegressionModel>
</PMML>

我的输出xml是:

<?xml version="1.0" encoding="utf-8"?>
<Predictors xmlns:ns="some:ns" xmlns:rs="http://www.dmg.org/PMML-4_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Predictor coefficient="-167.307903919999" name="__INTERCEPT__" value=""/>
  <Predictor coefficient="-0.0747629275586869" name="ACTIVE_CUSTOMER" value="0"/>
  <Predictor coefficient="0.409965797830495" name="ACTIVE_CUSTOMER" value="1"/>
  <Predictor coefficient="" name="SEGMENT" value="0"/>
  <Predictor coefficient="" name="SEGMENT" value="1"/>
</Predictors>

我可以使用以下xslt实现此目的:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sap="http://www.sap.com/sapxsl" xmlns:ns="some:ns" xmlns:rs="http://www.dmg.org/PMML-4_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
  <xsl:output encoding="utf-8" indent="yes" method="xml"/>
  <xsl:strip-space elements="*"/>

  <xsl:key match="rs:ParamMatrix/rs:PCell" name="cell" use="@parameterName"/>
  <xsl:key match="rs:DataDictionary/rs:DataField" name="dataField" use="@name"/>

  <!-- identity transform -->
  <xsl:template match="node()|@*">
     <xsl:apply-templates select="node()|@*"/>
  </xsl:template>

  <xsl:template match="rs:GeneralRegressionModel">
    <!--MiningSchema-->
    <xsl:apply-templates select="rs:MiningSchema"/>

    <!--RegressionTable for predicted targetVariable targetCategory-->
    <Predictors>
      <xsl:apply-templates select="rs:ParameterList/rs:Parameter"/>
    </Predictors>

  </xsl:template>

    <xsl:template match="rs:Parameter[not(contains(@label, '='))][@name='P0000001']">
    <Predictor coefficient="{key('cell', @name)/@beta}" name="__INTERCEPT__" value=""/>
  </xsl:template>

  <xsl:template match="rs:Parameter[not(contains(@label, '='))][@name!='P0000001']">
    <Predictor coefficient="{key('cell', @name)/@beta}" name="{@label}" value=""/>
  </xsl:template>

  <xsl:template match="rs:Parameter[contains(@label, '=')]" name="split">
    <Predictor coefficient="{key('cell', @name)/@beta}" name="{substring-after(substring-before(@label,'='),'[')}" value="{substring-before(substring-after(@label,'='),']')}"/>
  </xsl:template>

</xsl:transform>

这个XSLT有效。 但是,我有两个问题: 1.在源xml的开头,有命名空间,例如'xmlns =“http://www.dmg.org/PMML-4_1”',可能是其他值。整个文档只使用这一个命名空间。目前在我的xslt中,我将命名空间设置为固定值'xmlns:rs =“http://www.dmg.org/PMML-4_1”',这是不正确的。如何在xslt中动态设置命名空间?

  1. 一旦我在xslt中设置了命名空间,它也会在输出xml中显示出来。如何从输出xml中删除此命名空间?
  2. 如果没问题,请你直接修改我的xslt以告诉我用法吗?

    非常感谢!!!

4 个答案:

答案 0 :(得分:1)

在命名空间中创建一个在运行时才知道的元素:

(a)将任何文字结果元素(例如<Predictor/>)更改为<xsl:element name="Predictor" namespace="{$ns}'/>

(b)将<xsl:copy/>的任何使用更改为<xsl:element name="{local-name()}" namespace="{$ns}'/>

(c)使用<xsl:copy-of/>修改后的身份模板将<xsl:element/>的任何使用更改为递归副本。

或者,与控制此XML词汇表的人交谈,并询问他们为何以这种方式滥用名称空间。

答案 1 :(得分:0)

如果您正在寻求使xsl命名空间不可知,以便您可以随意更改输入xml的命名空间,那么您需要分两个阶段运行转换。

如果您在xsl中包含以下内容并从xsl中移除所有命名空间引用 - uri和前缀 - (除了您希望在输出中看到的那些)

<xsl:template match="@*" mode="stripNS">
    <xsl:attribute name="{local-name(.)}"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
<xsl:template match="node()" mode="stripNS">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="node()|@*" mode="stripNS"/>
    </xsl:element>
</xsl:template>
<xsl:template match="/">
    <xsl:variable name="nakedXML">
        <xsl:apply-templates mode="stripNS"/>
    </xsl:variable>
    <xsl:apply-templates select="$nakedXML/*" />
</xsl:template>

root上的匹配始终是要执行的初始模板,无论输入命名空间如何。然后xml将使用&lt; xsl:element&gt;和&lt; attribute&gt;要在输入变量$ nakedXML中创建输入xml的表示,将删除所有名称空间。

从这一点开始,您可以使用&lt; apply-templates&gt;反对nakedXML。 注意,一些xsl处理器要求你用一个合适的node-set()函数包装$ nakeXML--每个处理器处理它的方式不同,所以请检查你的文档。

我应该补充一下,我并不完全赞同这种技巧。它对性能有重大影响,剥离命名空间有可能在以后产生混淆。 IMO,当使用命名空间编写内容时,应始终使用该命名空间来引用内容。

答案 2 :(得分:0)

在我之前的回答中发表评论后:

每当您需要获取当前节点的名称空间时,您应该遍历名称空间轴。如果我们假设在根节点中声明了 all 您的docuemnt命名空间,则可以使用xpath“/ * / namespace :: *”来获取所有命名空间的节点集。

因此,对于您的示例输入,类似这样......

  <xsl:for-each select="/*/namespace::*">
       <namespace prefix="{name()}" uri="{.}"/>
  </xsl:for-each>

会给你

<namespace prefix="" uri="http://www.dmg.org/PMML-4_1"/>
<namespace prefix="xsi" uri="http://www.w3.org/2001/XMLSchema-instance"/>
<namespace prefix="xml" uri="http://www.w3.org/XML/1998/namespace"/>

如果您只想要根节点的默认名称空间URI:

<xsl:value-of select="/*/namespace::*[not(name())]"/>

答案 3 :(得分:0)

如果将以下样式表应用于输入XML:

XSLT 1.0(a)

<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="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*[namespace-uri()=/*/namespace::*[not(name())]]">
    <xsl:element name="{local-name()}" namespace="urn:x-my:constant-namespace">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

它会将(未知)默认命名空间中的所有元素移动到已知且常量的命名空间urn:x-my:constant-namespace

<?xml version="1.0" encoding="UTF-8"?>
<PMML xmlns="urn:x-my:constant-namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4.1" xsi:schemaLocation="http://www.dmg.org/PMML-4_1 pmml-4-1.xsd">
  <Header copyright="(C) Copyright IBM Corp. 1989, 2014.">
    <Application name="IBM SPSS Statistics 23.0" version="23.0.0.0"/>
  </Header>
  <GeneralRegressionModel algorithmName="multinomialLogistic" functionName="classification" modelType="multinomialLogistic" targetVariableName="CLASS">
    <MiningSchema>
      <MiningField missingValueTreatment="asIs" name="CLASS" usageType="predicted"/>
      <MiningField missingValueTreatment="asIs" name="ACTIVE_CUSTOMER" usageType="active"/>
      <MiningField missingValueTreatment="asIs" name="SEGMENT" usageType="active"/>
    </MiningSchema>
    <ParameterList>
      <Parameter label="Konstanter Term" name="P0000001"/>
      <Parameter label="[ACTIVE_CUSTOMER=0]" name="P0000002"/>
      <Parameter label="[ACTIVE_CUSTOMER=1]" name="P0000003"/>
      <Parameter label="[SEGMENT=0]" name="P00000004"/>
      <Parameter label="[SEGMENT=1]" name="P00000005"/>
    </ParameterList>
    <ParamMatrix>
      <PCell beta="-167.307903919999" df="1" parameterName="P0000001" targetCategory="1"/>
      <PCell beta="-0.0747629275586869" df="1" parameterName="P0000002" targetCategory="1"/>
      <PCell beta="0.409965797830495" df="1" parameterName="P0000003" targetCategory="1"/>
      <PCell beta="-1.03190717557433" df="1" parameterName="P0000004" targetCategory="1"/>
      <PCell beta="0.904157514089376" df="1" parameterName="P0000005" targetCategory="1"/>
    </ParamMatrix>
  </GeneralRegressionModel>
</PMML>

然后,您可以将第二个样式表应用于结果,例如:

XSLT 1.0(b)

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rs="urn:x-my:constant-namespace" 
exclude-result-prefixes="rs">
<xsl:output encoding="utf-8" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>

<xsl:key match="rs:PCell" name="cell" use="@parameterName"/>

<xsl:template match="/">
    <Predictors>
          <xsl:apply-templates/>
    </Predictors>
</xsl:template>

<xsl:template match="rs:Parameter[not(contains(@label, '='))][@name='P0000001']">
    <Predictor coefficient="{key('cell', @name)/@beta}" name="__INTERCEPT__" value=""/>
</xsl:template>

<xsl:template match="rs:Parameter[not(contains(@label, '='))][@name!='P0000001']">
    <Predictor coefficient="{key('cell', @name)/@beta}" name="{@label}" value=""/>
</xsl:template>

<xsl:template match="rs:Parameter[contains(@label, '=')]">
    <Predictor coefficient="{key('cell', @name)/@beta}" name="{substring-after(substring-before(@label,'='),'[')}" value="{substring-before(substring-after(@label,'='),']')}"/>
</xsl:template>

</xsl:stylesheet>

并收到:

<?xml version="1.0" encoding="utf-8"?>
<Predictors>
  <Predictor coefficient="-167.307903919999" name="__INTERCEPT__" value=""/>
  <Predictor coefficient="-0.0747629275586869" name="ACTIVE_CUSTOMER" value="0"/>
  <Predictor coefficient="0.409965797830495" name="ACTIVE_CUSTOMER" value="1"/>
  <Predictor coefficient="" name="SEGMENT" value="0"/>
  <Predictor coefficient="" name="SEGMENT" value="1"/>
</Predictors>