Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XML to JSON to XML #25

Open
jaylach opened this issue Feb 28, 2013 · 4 comments
Open

XML to JSON to XML #25

jaylach opened this issue Feb 28, 2013 · 4 comments

Comments

@jaylach
Copy link

jaylach commented Feb 28, 2013

I recently ran into an issue when using json4s for XML to JSON to XML. Here's what I ran into:

XML to JSON works wonderfully. My XML gets (for the most part) parsed into a JSON graph correctly. The problem arises when I go and take that parsed JSON and try to convert it back to XML.

I know this scenario seems strange, but bear with me. I won't get into why but I can promise this use case makes sense for my application's needs.

Anyways when parsing XML to JSON and back to XML, where the original xml contained attributes, the final XML has those attributes as elements instead. For example

// Original XML
<element attribute="value"></element>

// Parsed JSON
{ 
    "element": {
        "attribute": "value" 
    } 
}

// Parsed XML
<element>
    <attribute>value</attribute>
</element>

This was not kosher for me as I required those attributes to be there AS ATTRIBUTES and NOT as elements. So with all that said, I took the liberty of digging into the json4s/lift-json code, pulling out the toJson and toXml methods, and modifying them for my needs.

I would normally submit these changes back in a pull request, but I'm still fairly new to Scala and I'm not too sure how common my use case is. So instead of submitting a pull request, I'll outline my changes here. If someone else runs into this issue, they'll have a solution here. Should you guys decide this should be part of the source I'll go ahead and fork -> submit a pull request.

Note that I did not make these changes inside the source (I have not forked and built my own version). Instead I pulled the toJson and toXml methods out and put them directly in my source. Not the best approach, but it works for my current needs (currently at Proof of Concept stage).

So, on to the changes... First was the toJson method. There is a method called buildAttrs. I changed this to be:

def buildAttrs(n: Node) = n.attributes.map((a: MetaData) => ("@" + a.key, XValue(a.value.text))).toList

What this change does is, for attributes, it appends the key with the "@" symbol. That was easy :)

Next up was the toXml method to handle those "@key" JSON keys. First was to change the XmlNode class definition to use attributes.

private class XmlNode(name: String, children: Seq[Node], attributes: MetaData = xml.Null) extends Elem(null, name, attributes, TopScope, children :_*)

Last was to change the actual toXml method. The only change required here was to the match on JObject(fields) inside the toXml method (which is in the toXml method, hah).

// Inside toXml(json: JValue) ... toXml(name: String, json: JValue): NodeSeq
case JObject(fields) => {
    // We need to build our attributes MetaData object, if we have any.
    var attributes: MetaData = xml.Null

    for ( field <- fields ) {
      field match {
        case (n, v) if n.startsWith("@") => {
            // If our name (key) starts with "@", remove the "@" and create our attribute
            val name = n.substring(1)
            attributes = new UnprefixedAttribute(name, v.extract[String], attributes)
        }
        case _ => None
      }
    }

    new XmlNode(name, fields flatMap { 
        // Only "toXml" fields that don't start with an "@", since we already handled those as attributes above.
        case (n, v) if !n.startsWith("@") => toXml(n, v) 
        case _ => Text("")
    }, attributes)
}

With these changes, the above XML to JSON to XML example properly parses back to XML as...

// Parsed XML
<element attribute="value"></element>

Hopefully someone will find these changes useful. As mentioned, if you powers to be deem this change worth pushing back, I'll gladly make the changes in the source and submit a pull request :)

@casualjim
Copy link
Member

sorry I had only looked at the code first. Yes pull request is great.

@tribbloid
Copy link

I'm also looking for this feature
+1 on merge and close

@agajji
Copy link

agajji commented Aug 31, 2016

Any plans to merge this code?

@magnolia-k
Copy link
Contributor

I will write a patch for this proposal if there is a request at this time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

6 participants