Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to convert XML attribute to the node 2

Status
Not open for further replies.

webstudyer

Programmer
Apr 24, 2006
7
CA
I have an xml file like

oldxml.xml


<ResultSet>
<data_service>
<Employeeprofile>
<row emp_name="one" org_cd="73700" rpt_to_org_cd="11111" lev="2" />
<row emp_name="four" org_cd="73656" rpt_to_org_cd="73700" lev="3" />
<row emp_name="five" org_cd="75425" rpt_to_org_cd="73700" lev="3" />
<row emp_name="three" org_cd="73723" rpt_to_org_cd="11111" lev="2" />
<row emp_name="two" org_cd="73708" rpt_to_org_cd="11111" lev="2" />
<row emp_name="Six" org_cd="73651" rpt_to_org_cd="73708" lev="3" />
</Employeeprofile>
</data_service>
</ResultSet>

I want to generate the new XML which is like this:

newxml.xml


<ResultSet>
<branch id="one">
<branchtext>one</branchtext>
<leaf>
<leafText>four</leafText>
</leaf>
<leaf>
<leafText>five</leafText>
</leaf>
</branch>
<branch id="three">
<branchtext>three</branchtext>
</branch>
<branch id="two">
<branchtext>two</branchtext>
<leaf>
<leafText>six</leafText>
</leaf>
</branch>
</ResultSet>

What is the way to do it? Using XSL? I am new in XML XSL, so would you please show me what I should do?

I use ASP to show the new xml.

Thanks in advance!

Nyan

 
How far you go from seeing this special realization depends on your own.

[tt]<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl=" <xsl:eek:utput method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/ResultSet">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="./data_service/Employeeprofile/row[position() mod 3 = 1]" />
</xsl:element>
</xsl:template>
<xsl:template match="ResultSet/data_service/Employeeprofile/row">
<xsl:element name="branch">
<xsl:attribute name="id">
<xsl:value-of select="@emp_name" />
</xsl:attribute>
<xsl:element name="branchtext">
<xsl:value-of select="@emp_name" />
</xsl:element>
<xsl:element name="leaf">
<xsl:element name="leafText">
<xsl:value-of select="following-sibling::*[1]/@emp_name" />
</xsl:element>
</xsl:element>
<xsl:element name="leaf">
<xsl:element name="leafText">
<xsl:value-of select="following-sibling::*[2]/@emp_name" />
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
[/tt]
 
Thanks tsuji!

Here is my asp code:

dim xslinputPath1
'which the code you posted
xslinputPath1 = "convert.xsl"
set objxsl = Server.CreateObject("Msxml2.FreeThreadedDOMDocument")
objxsl.async = false
objxsl.resolveExternals = false
objxsl.validateOnParse = false
objxsl.load xslinputPath1
if (objxsl.parseError.errorCode <> 0) then
Response.Write "XML error - " & "<br>"
Response.Write "Error Reason: " & objxsl.parseError.reason & "<br>"
Response.Write "Source: " & objxsl.parseError.srcText & "<br>"
Response.Write "Error Line: " & objxsl.parseError.line & "<br>"
Response.Write "Error Position: " & objxsl.parseError.linepos & "<br>"
end if

set objxml = Server.CreateObject("Microsoft.XMLDOM")
objxml.async = false
objxml.resolveExternals = false
objxml.validateOnParse = false
'which is the code I have it here
objxml.load ("oldxml.xml")

if (objxml.parseError.errorCode <> 0) then
Response.Write "XML error - " & "<br>"
Response.Write "Error Reason: " & objxml.parseError.reason & "<br>"
Response.Write "Source: " & objxml.parseError.srcText & "<br>"
Response.Write "Error Line: " & objxml.parseError.line & "<br>"
Response.Write "Error Position: " & objxml.parseError.linepos & "<br>"
end if


Dim out
out = objxml.transformNodeToObject(objxsl)
Response.Write out.xml
out.save ("newxml.xml")

The result is nothing, no xml file can display on the screen. I right click to view the source is like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=windows-1252"></HEAD>
<BODY></BODY></HTML>

I dont know what is wrong with my code. I want to get the new format xml. Thanks for your help.

Nyan
 
The problem resolved.

"out" has to be defined like this
Dim out
Set out = Server.CreateObject("Microsoft.XMLDOM")
out.async = false
out.loadXML objxml.transformNode(objxsl)
out.save ("newxml.xml")
 
That's because you use transformNodeToObject. You can simply use transformNode. If you want to save a persistent copy as well, just use loadxml and re-use the same object objxml.
[tt]
Dim out

'replaced
'out = objxml.transformNodeToObject(objxsl)
'Response.Write out.xml
'out.save ("newxml.xml")

out=objxml.transformNode(objxsl)
Response.Write out
objxml.loadxml out
objxml.save "newxml.xml"
[/tt]
 
Hi tsuji

<branch id="three">
<branchtext>three</branchtext>
</branch>

should put on the up level(because of lev="2" ), here is the correct xml

<ResultSet>
<branch id="one">
<branchtext>one</branchtext>
<leaf>
<leafText>four</leafText>
</leaf>
<leaf>
<leafText>five</leafText>
</leaf>
</branch>
<branch id="three">
<branchtext>three</branchtext>
</branch>
<branch id="two">
<branchtext>two</branchtext>
<leaf>
<leafText>six</leafText>
</leaf>
</branch>
</ResultSet>


Use your xsl, the output is like:


<?xml version="1.0" encoding="UTF-16"?>
<ResultSet>
<branch id="one">
<branchtext>one</branchtext>
<leaf>
<leafText>four</leafText>
</leaf>
<leaf>
<leafText>five</leafText>
</leaf>
</branch>
<branch id="three">
<branchtext>three</branchtext>
<leaf>
<leafText>two</leafText>
</leaf>
<leaf>
<leafText>Six</leafText>
</leaf>
</branch>
</ResultSet>


How to fix this xsl?

Thanks for your help!

Nyan
 
I see. After you point it out and I re-read your newxml.xml. Sure I'd mis=read your first post.

Could you state the internal logic of the newxml.xml so that I can re-construct the xsl? I'm calling the day off. I will read your input on the internal logic and do it again tomorrow.
 
tsuji:

Sorry for my unclear guide. I modified my oldxml.xml, let it more clearer.

oldxml.xml

<ResultSet>
<data_service>
<Employeeprofile>
<row emp_name="one" org_cd="73700" rpt_to_org_cd="11111" lev="2" />
<row emp_name="four" org_cd="73656" rpt_to_org_cd="73700" lev="3" />
<row emp_name="five" org_cd="75425" rpt_to_org_cd="73700" lev="3" />
<row emp_name="three" org_cd="73723" rpt_to_org_cd="11111" lev="2" />
<row emp_name="two" org_cd="73708" rpt_to_org_cd="11111" lev="2" />
<row emp_name="Six" org_cd="73651" rpt_to_org_cd="73708" lev="3" />
<row emp_name="Seven" org_cd="73632" rpt_to_org_cd="73651" lev="4" />
<row emp_name="Eight" org_cd="73229" rpt_to_org_cd="73651" lev="4" />
<row emp_name="nine" org_cd="74023" rpt_to_org_cd="73651" lev="4" />
<row emp_name="ten" org_cd="73989" rpt_to_org_cd="11111" lev="2" />
</Employeeprofile>
</data_service>
</ResultSet>

lev="2" is same level. Then lev=3, lev=4...
every level may have leaves or may not have leaves, like emp_name="two", it has no leaf.

Attribute rpt_to_org_cd is the value pointing to the parent. for example emp_name="Eight", rpt_to_org_cd ="73651", its parents' node is same as emp_name="Seven" and emp_name="nine" which is emp_name="Six" org_cd="73651"

So the newxml.xml should be like this:


<ResultSet>
<branch id="one">
<branchText>one</branchText>
<leaf>
<leafText>four</leafText>
</leaf>
<leaf>
<leafText>five</leafText>
</leaf>
</branch>

<branch id="three">
<branchText>three</branchText>
</branch>

<branch id="two">
<branchText>two</branchText>
<branch id="Six">
<branchText>Six</branchText>
<leaf>
<leafText>Seven</leafText>
</leaf>
<leaf>
<leafText>Eight</leafText>
</leaf>
<leaf>
<leafText>nine</leafText>
</leaf>
</branch>
</branch>

<branch id="ten">
<branchText>ten</branchText>
</branch>

</ResultSet>

Does it make sense.Thanks!

Nyan
 
This is one-level deep only, should work as expected for the original xml data. It would give a flat structure on leaf though. To make it nested at the leaf level, you should make a recursive call for the next sibling with level less than the current. I have not developed this yet. Some device in the xsl is for the preparation of this end goal. Still a bit of a patch work. Need some undisturbed time to generalize it. May be you can finish it or make a better approach out of it?
[tt]
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl=" <xsl:eek:utput method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/ResultSet">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="./data_service/Employeeprofile/row[@lev = 2]" />
</xsl:element>
</xsl:template>
<xsl:template match="ResultSet/data_service/Employeeprofile/row[@lev = 2]">
<xsl:variable name="refid" select="generate-id()" />
<xsl:element name="branch">
<xsl:attribute name="id">
<xsl:value-of select="@emp_name" />
</xsl:attribute>
<xsl:element name="branchText">
<xsl:value-of select="@emp_name" />
</xsl:element>
<xsl:call-template name="sublev">
<xsl:with-param name="x_id" select="$refid" />
<xsl:with-param name="x_lev" select="@lev" />
<xsl:with-param name="x_node" select="current()" />
</xsl:call-template>
</xsl:element>
</xsl:template>
<xsl:template name="sublev">
<xsl:param name="x_id" />
<xsl:param name="x_lev" />
<xsl:param name="x_node" />
<xsl:for-each select="$x_node/following-sibling::row[@lev &gt; 2]">
<xsl:call-template name="sublev_work">
<xsl:with-param name="ref_id" select="$x_id" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="sublev_work" match="ResultSet/data_service/Employeeprofile/row[@lev &gt; 2]">
<xsl:param name="ref_id" />
<xsl:variable name="refbranch" select="generate-id(preceding-sibling::row[@lev = 2][1])" />
<xsl:if test="$ref_id = $refbranch">
<xsl:element name="leaf">
<xsl:element name="leafText">
<xsl:value-of select="@emp_name" />
</xsl:element>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
[/tt]
 
Or, more simply:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:template match="/">
    <ResultSet>
      <xsl:apply-templates select="ResultSet/data_service/Employeeprofile/row[@lev = 2]"/>
    </ResultSet>
  </xsl:template>
  <xsl:template match="row">
    <branch id="@emp_name">
      <branchtext>
        <xsl:value-of select="@emp_name"/>
      </branchtext>
      <xsl:call-template name="IterateRows">
        <xsl:with-param name="rows" select="following-sibling::node()"/>
      </xsl:call-template>
    </branch>
  </xsl:template>
  <xsl:template name="IterateRows">
    <xsl:param name="rows"/>
    <xsl:if test="$rows[1]/@lev = 3">
      <leaf>
        <leaftext>
          <xsl:value-of select="$rows[1]/@emp_name"/>
        </leaftext>
      </leaf>
      <xsl:call-template name="IterateRows">
        <xsl:with-param name="rows" select="$rows[position() &gt; 1]"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

Jon

"I don't regret this, but I both rue and lament it.
 
tsuji,

Is it possible you can show me how to make a recursive call ? I could not figure it out for 2 weeks. I am newbie in this field. Thanks!

Nyan
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top