XSLT with Identity Template with Multiple Match Condition and Removal of unused nodes

半世苍凉 提交于 2020-01-17 08:02:20

问题


I have below xml and i need to convert to following xml using xslt

In the input xml i have referenced as topmost node which has subnodes as follows:

<?xml version="1.0"?>
<referenced>
  <name>PocTree/PocTree.services:getReferencesForServices</name>
  <LOCK_STATUS>3</LOCK_STATUS>
  <type>
    <svc_type>flow</svc_type>
    <svc_subtype>default</svc_subtype>
  </type>
  <path/>
  <isPub>false</isPub>
  <isNotification>false</isNotification>
  <isFlowServiceDisabled>false</isFlowServiceDisabled>
  <status>reference</status>
  <reference>
    <name>WmRoot/wm.server.ns.dependency:getReferenced</name>
    <LOCK_STATUS>2</LOCK_STATUS>
    <type>
      <svc_type>java</svc_type>
      <svc_subtype>unknown</svc_subtype>
    </type>
    <path>/Flow Path;1.0/INVOKE;0</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>resolved</status>
  </reference>
  <reference>
    <name>WmPublic/pub.xml:documentToXMLString</name>
    <LOCK_STATUS>2</LOCK_STATUS>
    <type>
      <svc_type>java</svc_type>
      <svc_subtype>unknown</svc_subtype>
    </type>
    <path>/Flow Path;1.0/INVOKE;1</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>resolved</status>
  </reference>
  <reference>
    <name>PocTree/PocTree.services:jkl</name>
    <LOCK_STATUS>3</LOCK_STATUS>
    <type>
      <svc_type>xsltservice</svc_type>
      <svc_subtype>unknown</svc_subtype>
    </type>
    <path>/Flow Path;1.0/INVOKE;2</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>resolved</status>
  </reference>
  <reference>
    <name>WmPublic/pub.xml:xmlStringToXMLNode</name>
    <LOCK_STATUS>2</LOCK_STATUS>
    <type>
      <svc_type>java</svc_type>
      <svc_subtype>unknown</svc_subtype>
    </type>
    <path>/Flow Path;1.0/INVOKE;3</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>resolved</status>
  </reference>
  <reference>
    <name>WmPublic/pub.xml:xmlNodeToDocument</name>
    <LOCK_STATUS>2</LOCK_STATUS>
    <type>
      <svc_type>java</svc_type>
      <svc_subtype>unknown</svc_subtype>
    </type>
    <path>/Flow Path;1.0/INVOKE;4</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>resolved</status>
  </reference>
  <reference>
    <name>PocTree/PocTree.services:ghi</name>
    <LOCK_STATUS>4</LOCK_STATUS>
    <type>
      <svc_type>xsltservice</svc_type>
      <svc_subtype>unknown</svc_subtype>
    </type>
    <path>/Flow Path;1.0/INVOKE;5</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>resolved</status>
  </reference>
  <reference>
    <name>WxPackageTree/WxPackageTree.doc:NodeInfo</name>
    <LOCK_STATUS>2</LOCK_STATUS>
    <type>
      <type_name>record</type_name>
    </type>
    <path>/Service Path;1.0/signature;2;subPath;"/nodes;4;0;WxPackageTree.doc:NodeInfo"</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>reference</status>
    <reference>
      <name>WxPackageTree/WxPackageTree.doc:NodeInfo</name>
      <LOCK_STATUS>2</LOCK_STATUS>
      <type>
        <type_name>record</type_name>
      </type>
      <path>/children;4;1;WxPackageTree.doc:NodeInfo</path>
      <isPub>false</isPub>
      <isNotification>false</isNotification>
      <isFlowServiceDisabled>false</isFlowServiceDisabled>
      <status>recursive</status>
    </reference>
    <reference>
    <name>PocTree/PocTree.docs:nodeInfo</name>
    <LOCK_STATUS>4</LOCK_STATUS>
    <type>
      <type_name>record</type_name>
    </type>
    <path>/Flow Path;1.0/MAP;6/MAPCOPY;1/to_field;-2;subPath;"/nodeInfo;4;0;PocTree.docs:nodeInfo"</path>
    <path>/Flow Path;1.0/MAP;6/MAPCOPY;2/to_field;-2;subPath;"/nodeInfo;4;0;PocTree.docs:nodeInfo"</path>
    <path>/Flow Path;1.0/MAP;6/MAPCOPY;3/to_field;-2;subPath;"/nodeInfo;4;0;PocTree.docs:nodeInfo"</path>
    <isPub>false</isPub>
    <isNotification>false</isNotification>
    <isFlowServiceDisabled>false</isFlowServiceDisabled>
    <status>reference</status>
    <reference>
      <name>PocTree/PocTree.docs:nodeInfo</name>
      <LOCK_STATUS>4</LOCK_STATUS>
      <type>
        <type_name>record</type_name>
      </type>
      <path>/children;4;1;PocTree.docs:nodeInfo</path>
      <isPub>false</isPub>
      <isNotification>false</isNotification>
      <isFlowServiceDisabled>false</isFlowServiceDisabled>
      <status>recursive</status>
    </reference>
  </reference>
  </reference>
</referenced> 

Expected Output XML structure should be something like :

 <?xml version="1.0"?>
    <nodeInfo>
      <name>PocTree/PocTree.services:getReferencesForServices</name>
      <LOCK_STATUS>3</LOCK_STATUS>
      <type>flow</type>
      <path/>
      <isPub>false</isPub>
      <isNotification>false</isNotification>
      <isFlowServiceDisabled>false</isFlowServiceDisabled>
      <status>reference</status>
      <children>
        <name>WmRoot/wm.server.ns.dependency:getReferenced</name>
        <LOCK_STATUS>2</LOCK_STATUS>
        <type>java</type>
        <path>/Flow Path;1.0/INVOKE;0</path>
        <isPub>false</isPub>
        <isNotification>false</isNotification>
        <isFlowServiceDisabled>false</isFlowServiceDisabled>
        <status>resolved</status>
      </children>
      <children>
        <name>WmPublic/pub.xml:documentToXMLString</name>
        <LOCK_STATUS>2</LOCK_STATUS>
        <type>java</type>
        <path>/Flow Path;1.0/INVOKE;1</path>
        <isPub>false</isPub>
        <isNotification>false</isNotification>
        <isFlowServiceDisabled>false</isFlowServiceDisabled>
        <status>resolved</status>
      </reference>
      <children>
        <name>PocTree/PocTree.services:jkl</name>
        <LOCK_STATUS>3</LOCK_STATUS>
        <type>xsltservice</type>
        <path>/Flow Path;1.0/INVOKE;2</path>
        <isPub>false</isPub>
        <isNotification>false</isNotification>
        <isFlowServiceDisabled>false</isFlowServiceDisabled>
        <status>resolved</status>
      </children>
      <children>
        <name>WmPublic/pub.xml:xmlStringToXMLNode</name>
        <LOCK_STATUS>2</LOCK_STATUS>
        <type>java</type>
        <path>/Flow Path;1.0/INVOKE;3</path>
        <isPub>false</isPub>
        <isNotification>false</isNotification>
        <isFlowServiceDisabled>false</isFlowServiceDisabled>
        <status>resolved</status>
      </children>
      <children>
        <name>WmPublic/pub.xml:xmlNodeToDocument</name>
        <LOCK_STATUS>2</LOCK_STATUS>
        <type>java</type>
        <path>/Flow Path;1.0/INVOKE;4</path>
        <isPub>false</isPub>
        <isNotification>false</isNotification>
        <isFlowServiceDisabled>false</isFlowServiceDisabled>
        <status>resolved</status>
      </children>
      <children>
        <name>PocTree/PocTree.services:ghi</name>
        <LOCK_STATUS>4</LOCK_STATUS>
        <type>xsltservice</type>
        <path>/Flow Path;1.0/INVOKE;5</path>
        <isPub>false</isPub>
        <isNotification>false</isNotification>
        <isFlowServiceDisabled>false</isFlowServiceDisabled>
        <status>resolved</status>
      </children>
    </nodeInfo>

But the criteria to obtain expected output xml is that from the value of one of the subnodes of input xml which is this section

  <type>
        <svc_type>flow</svc_type>
        <svc_subtype>default</svc_subtype>
      </type>

Which sometime does have a extra tag like this meaning can have either , child nodes or only .

 <type>
    <type_name>record</type_name>
  </type>

Now the expected Output XML should be designed such way that chose only those <refrence> tags from Input xml where <svc_type> has value of 'flow' or 'javaservice' or 'xsltservice' and omit those <refrence> tags which has <type_name> belonging to <type> parent node with any value.

Also the content of <svc_type> should be mapped to value of <type> and output xml should not contain subnodes <svc_type> and <svc_subtype> for its parent node <type>.

Kindly help on this topic.

Including the xslt written to achieve filtering of input XML

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>

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

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

    <xsl:template  match="(reference[type/svc_type[contains(., 'flow') or contains(., 'java') or contains(., 'xsltservice')]]) and (reference[type/type_name[not(contains(.,'record'))]])">
        <children>
            <xsl:apply-templates />
        </children>
    </xsl:template>
</xsl:stylesheet>

But above xslt still does not cover this part - <svc_type> should be mapped to value of <type> and output xml should not contain subnodes <svc_type> and <svc_subtype> for its parent node <type>.


回答1:


You need to reverse your logic. Instead of thinking about what nodes you wish to copy, you need to think of what you don't want to copy, and write a template to match these, and ignore them.

The identity template will then handle all the things you want to copy.

So, you say you want to include <reference> tags from Input xml where <svc_type> has a value of 'flow' or 'javaservice' or 'xsltservice'. The converse of this is that you want to exclude such <reference> which don't have a <svc_type> set to any of those three values:

<xsl:template match="reference[type/svc_type[not(contains(., 'flow') or contains(., 'java') or contains(., 'xsltservice'))]]" />

You other rule is already one about removal, so that can be done straight-forwardly without any logic reversal

<xsl:template match="reference[type/type_name]" priority="2" />

The priority is probably not needed here, unless you could have a reference tag which had both a type/type_name and a type/svc_type, in which case there would be a conflict between templates

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>

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

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

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

    <xsl:template match="type[svc_type]">
        <type>
            <xsl:value-of select="svc_type" />
        </type>
    </xsl:template>

    <xsl:template match="reference[type/svc_type[not(contains(., 'flow') or contains(., 'java') or contains(., 'xsltservice'))]]" />

    <xsl:template match="reference[type/type_name]" priority="2" />
</xsl:stylesheet>

Also note the addition of the template to turn to handle you transformation on svc_type to just type.



来源:https://stackoverflow.com/questions/40386383/xslt-with-identity-template-with-multiple-match-condition-and-removal-of-unused

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!