* minor: fix log message printed when unrecognized elements are found in inventory rest input xml
parent
c8abe037a5
commit
5a0fa4f34c
|
@ -247,10 +247,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
|
/// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
|
||||||
/// is decoded and stored in the database, identified by the supplied UUID.
|
/// is decoded and stored in the database, identified by the supplied UUID.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
private void DoPut(AssetRequestData rdata)
|
private void DoPut(AssetRequestData rdata)
|
||||||
{
|
{
|
||||||
|
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
bool created = false;
|
bool created = false;
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// This property is declared locally because it is used a lot and
|
/// This property is declared locally because it is used a lot and
|
||||||
/// brevity is nice.
|
/// brevity is nice.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
internal string MsgId
|
internal string MsgId
|
||||||
{
|
{
|
||||||
get { return Rest.MsgId; }
|
get { return Rest.MsgId; }
|
||||||
|
@ -139,7 +138,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// <param name=response>Outbound HTTP request information</param>
|
/// <param name=response>Outbound HTTP request information</param>
|
||||||
/// <param name=qPrefix>REST service domain prefix</param>
|
/// <param name=qPrefix>REST service domain prefix</param>
|
||||||
/// <returns>A RequestData instance suitable for this service</returns>
|
/// <returns>A RequestData instance suitable for this service</returns>
|
||||||
|
|
||||||
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
|
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||||
{
|
{
|
||||||
return (RequestData) new InventoryRequestData(request, response, prefix);
|
return (RequestData) new InventoryRequestData(request, response, prefix);
|
||||||
|
@ -152,7 +150,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// It handles all aspects of inventory REST processing, i.e. /admin/inventory
|
/// It handles all aspects of inventory REST processing, i.e. /admin/inventory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=hdata>A consolidated HTTP request work area</param>
|
/// <param name=hdata>A consolidated HTTP request work area</param>
|
||||||
|
|
||||||
private void DoInventory(RequestData hdata)
|
private void DoInventory(RequestData hdata)
|
||||||
{
|
{
|
||||||
InventoryRequestData rdata = (InventoryRequestData) hdata;
|
InventoryRequestData rdata = (InventoryRequestData) hdata;
|
||||||
|
@ -295,7 +292,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}",
|
Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}",
|
||||||
MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
|
MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
|
||||||
|
|
||||||
|
|
||||||
lock (rdata)
|
lock (rdata)
|
||||||
{
|
{
|
||||||
if (!rdata.HaveInventory)
|
if (!rdata.HaveInventory)
|
||||||
|
@ -373,7 +369,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// corresponding subtree based upon node name.
|
/// corresponding subtree based upon node name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=rdata>HTTP service request work area</param>
|
/// <param name=rdata>HTTP service request work area</param>
|
||||||
|
|
||||||
private void DoGet(InventoryRequestData rdata)
|
private void DoGet(InventoryRequestData rdata)
|
||||||
{
|
{
|
||||||
rdata.initXmlWriter();
|
rdata.initXmlWriter();
|
||||||
|
@ -439,7 +434,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// context identified by the URI.
|
/// context identified by the URI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=rdata>HTTP service request work area</param>
|
/// <param name=rdata>HTTP service request work area</param>
|
||||||
|
|
||||||
private void DoExtend(InventoryRequestData rdata)
|
private void DoExtend(InventoryRequestData rdata)
|
||||||
{
|
{
|
||||||
bool created = false;
|
bool created = false;
|
||||||
|
@ -480,7 +474,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
// [3] A (possibly empty) set of assets.
|
// [3] A (possibly empty) set of assets.
|
||||||
// If all of these are empty, then the POST is a harmless no-operation.
|
// If all of these are empty, then the POST is a harmless no-operation.
|
||||||
|
|
||||||
XmlInventoryCollection entity = ReconstituteEntity(rdata);
|
XmlInventoryCollection entity = ReconstituteEntity(rdata);
|
||||||
|
|
||||||
// Inlined assets can be included in entity. These must be incorporated into
|
// Inlined assets can be included in entity. These must be incorporated into
|
||||||
// the asset database before we attempt to update the inventory. If anything
|
// the asset database before we attempt to update the inventory. If anything
|
||||||
|
@ -667,7 +661,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// during the reconstitution process.
|
/// during the reconstitution process.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=rdata>HTTP service request work area</param>
|
/// <param name=rdata>HTTP service request work area</param>
|
||||||
|
|
||||||
private void DoUpdate(InventoryRequestData rdata)
|
private void DoUpdate(InventoryRequestData rdata)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -1303,7 +1296,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// <param name=rdata>HTTP service request work area</param>
|
/// <param name=rdata>HTTP service request work area</param>
|
||||||
/// <param name=i>The item to be formatted</param>
|
/// <param name=i>The item to be formatted</param>
|
||||||
/// <param name=indent>Pretty print indentation</param>
|
/// <param name=indent>Pretty print indentation</param>
|
||||||
|
|
||||||
private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent)
|
private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent)
|
||||||
{
|
{
|
||||||
Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}",
|
Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}",
|
||||||
|
@ -1349,7 +1341,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// that required it cannot be completed, and it fails accordingly.
|
/// that required it cannot be completed, and it fails accordingly.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=rdata>HTTP service request work area</param>
|
/// <param name=rdata>HTTP service request work area</param>
|
||||||
|
|
||||||
private InventoryFolderBase GetTrashCan(InventoryRequestData rdata)
|
private InventoryFolderBase GetTrashCan(InventoryRequestData rdata)
|
||||||
{
|
{
|
||||||
InventoryFolderBase TrashCan = null;
|
InventoryFolderBase TrashCan = null;
|
||||||
|
@ -1394,7 +1385,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=newf>Folder obtained from enclosed entity</param>
|
/// <param name=newf>Folder obtained from enclosed entity</param>
|
||||||
/// <param name=oldf>Folder obtained from the user's inventory</param>
|
/// <param name=oldf>Folder obtained from the user's inventory</param>
|
||||||
|
|
||||||
private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf)
|
private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf)
|
||||||
{
|
{
|
||||||
return (newf.Name != oldf.Name
|
return (newf.Name != oldf.Name
|
||||||
|
@ -1411,7 +1401,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=newf>Item obtained from enclosed entity</param>
|
/// <param name=newf>Item obtained from enclosed entity</param>
|
||||||
/// <param name=oldf>Item obtained from the user's inventory</param>
|
/// <param name=oldf>Item obtained from the user's inventory</param>
|
||||||
|
|
||||||
private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf)
|
private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf)
|
||||||
{
|
{
|
||||||
return (newf.Name != oldf.Name
|
return (newf.Name != oldf.Name
|
||||||
|
@ -1449,7 +1438,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// missing parent IDs are resolved).
|
/// missing parent IDs are resolved).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name=rdata>HTTP service request work area</param>
|
/// <param name=rdata>HTTP service request work area</param>
|
||||||
|
|
||||||
internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata)
|
internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata)
|
||||||
{
|
{
|
||||||
Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId);
|
Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId);
|
||||||
|
@ -1468,78 +1456,80 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
{
|
{
|
||||||
switch (ic.xml.NodeType)
|
switch (ic.xml.NodeType)
|
||||||
{
|
{
|
||||||
case XmlNodeType.Element :
|
case XmlNodeType.Element :
|
||||||
Rest.Log.DebugFormat("{0} StartElement: <{1}>",
|
Rest.Log.DebugFormat("{0} StartElement: <{1}>",
|
||||||
MsgId, ic.xml.Name);
|
|
||||||
switch (ic.xml.Name)
|
|
||||||
{
|
|
||||||
case "Folder" :
|
|
||||||
Rest.Log.DebugFormat("{0} Processing {1} element",
|
|
||||||
MsgId, ic.xml.Name);
|
MsgId, ic.xml.Name);
|
||||||
CollectFolder(ic);
|
switch (ic.xml.Name)
|
||||||
|
{
|
||||||
|
case "Folder" :
|
||||||
|
Rest.Log.DebugFormat("{0} Processing {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
CollectFolder(ic);
|
||||||
|
break;
|
||||||
|
case "Item" :
|
||||||
|
Rest.Log.DebugFormat("{0} Processing {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
CollectItem(ic);
|
||||||
|
break;
|
||||||
|
case "Asset" :
|
||||||
|
Rest.Log.DebugFormat("{0} Processing {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
CollectAsset(ic);
|
||||||
|
break;
|
||||||
|
case "Permissions" :
|
||||||
|
Rest.Log.DebugFormat("{0} Processing {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
CollectPermissions(ic);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
Rest.Log.DebugFormat("{0} Ignoring {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// This stinks, but the ReadElement call above not only reads
|
||||||
|
// the imbedded data, but also consumes the end tag for Asset
|
||||||
|
// and moves the element pointer on to the containing Item's
|
||||||
|
// element-end, however, if there was a permissions element
|
||||||
|
// following, it would get us to the start of that..
|
||||||
|
if (ic.xml.NodeType == XmlNodeType.EndElement &&
|
||||||
|
ic.xml.Name == "Item")
|
||||||
|
{
|
||||||
|
Validate(ic);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "Item" :
|
|
||||||
Rest.Log.DebugFormat("{0} Processing {1} element",
|
case XmlNodeType.EndElement :
|
||||||
MsgId, ic.xml.Name);
|
switch (ic.xml.Name)
|
||||||
CollectItem(ic);
|
{
|
||||||
break;
|
case "Folder" :
|
||||||
case "Asset" :
|
Rest.Log.DebugFormat("{0} Completing {1} element",
|
||||||
Rest.Log.DebugFormat("{0} Processing {1} element",
|
MsgId, ic.xml.Name);
|
||||||
MsgId, ic.xml.Name);
|
ic.Pop();
|
||||||
CollectAsset(ic);
|
break;
|
||||||
break;
|
case "Item" :
|
||||||
case "Permissions" :
|
Rest.Log.DebugFormat("{0} Completing {1} element",
|
||||||
Rest.Log.DebugFormat("{0} Processing {1} element",
|
MsgId, ic.xml.Name);
|
||||||
MsgId, ic.xml.Name);
|
Validate(ic);
|
||||||
CollectPermissions(ic);
|
break;
|
||||||
|
case "Asset" :
|
||||||
|
Rest.Log.DebugFormat("{0} Completing {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
break;
|
||||||
|
case "Permissions" :
|
||||||
|
Rest.Log.DebugFormat("{0} Completing {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
Rest.Log.DebugFormat("{0} Ignoring {1} element",
|
||||||
|
MsgId, ic.xml.Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default :
|
default :
|
||||||
Rest.Log.DebugFormat("{0} Ignoring {1} element",
|
Rest.Log.DebugFormat("{0} Ignoring: <{1}>:<{2}>",
|
||||||
MsgId, ic.xml.Name);
|
MsgId, ic.xml.NodeType, ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
// This stinks, but the ReadElement call above not only reads
|
|
||||||
// the imbedded data, but also consumes the end tag for Asset
|
|
||||||
// and moves the element pointer on to the containing Item's
|
|
||||||
// element-end, however, if there was a permissions element
|
|
||||||
// following, it would get us to the start of that..
|
|
||||||
if (ic.xml.NodeType == XmlNodeType.EndElement &&
|
|
||||||
ic.xml.Name == "Item")
|
|
||||||
{
|
|
||||||
Validate(ic);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XmlNodeType.EndElement :
|
|
||||||
switch (ic.xml.Name)
|
|
||||||
{
|
|
||||||
case "Folder" :
|
|
||||||
Rest.Log.DebugFormat("{0} Completing {1} element",
|
|
||||||
MsgId, ic.xml.Name);
|
|
||||||
ic.Pop();
|
|
||||||
break;
|
|
||||||
case "Item" :
|
|
||||||
Rest.Log.DebugFormat("{0} Completing {1} element",
|
|
||||||
MsgId, ic.xml.Name);
|
|
||||||
Validate(ic);
|
|
||||||
break;
|
|
||||||
case "Asset" :
|
|
||||||
Rest.Log.DebugFormat("{0} Completing {1} element",
|
|
||||||
MsgId, ic.xml.Name);
|
|
||||||
break;
|
|
||||||
case "Permissions" :
|
|
||||||
Rest.Log.DebugFormat("{0} Completing {1} element",
|
|
||||||
MsgId, ic.xml.Name);
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
Rest.Log.DebugFormat("{0} Ignoring {1} element",
|
|
||||||
MsgId, ic.xml.Name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
Rest.Log.DebugFormat("{0} [0] Ignoring: <{1}>:<2>",
|
|
||||||
MsgId, ic.xml.NodeType, ic.xml.Value);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1688,7 +1678,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// All context is reset whenever the effective folder changes
|
/// All context is reset whenever the effective folder changes
|
||||||
/// or an item is successfully validated.
|
/// or an item is successfully validated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
private void CollectItem(XmlInventoryCollection ic)
|
private void CollectItem(XmlInventoryCollection ic)
|
||||||
{
|
{
|
||||||
Rest.Log.DebugFormat("{0} Interpret item element", MsgId);
|
Rest.Log.DebugFormat("{0} Interpret item element", MsgId);
|
||||||
|
@ -1715,55 +1704,55 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
|
|
||||||
switch (ic.xml.Name)
|
switch (ic.xml.Name)
|
||||||
{
|
{
|
||||||
case "name" :
|
case "name" :
|
||||||
result.Name = ic.xml.Value;
|
result.Name = ic.xml.Value;
|
||||||
break;
|
break;
|
||||||
case "desc" :
|
case "desc" :
|
||||||
result.Description = ic.xml.Value;
|
result.Description = ic.xml.Value;
|
||||||
break;
|
break;
|
||||||
case "uuid" :
|
case "uuid" :
|
||||||
result.ID = new UUID(ic.xml.Value);
|
result.ID = new UUID(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "folder" :
|
case "folder" :
|
||||||
result.Folder = new UUID(ic.xml.Value);
|
result.Folder = new UUID(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "owner" :
|
case "owner" :
|
||||||
result.Owner = new UUID(ic.xml.Value);
|
result.Owner = new UUID(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "invtype" :
|
case "invtype" :
|
||||||
result.InvType = Int32.Parse(ic.xml.Value);
|
result.InvType = Int32.Parse(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "creator" :
|
case "creator" :
|
||||||
result.Creator = new UUID(ic.xml.Value);
|
result.Creator = new UUID(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "assettype" :
|
case "assettype" :
|
||||||
result.AssetType = Int32.Parse(ic.xml.Value);
|
result.AssetType = Int32.Parse(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "groupowned" :
|
case "groupowned" :
|
||||||
result.GroupOwned = Boolean.Parse(ic.xml.Value);
|
result.GroupOwned = Boolean.Parse(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "groupid" :
|
case "groupid" :
|
||||||
result.GroupID = new UUID(ic.xml.Value);
|
result.GroupID = new UUID(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "flags" :
|
case "flags" :
|
||||||
result.Flags = UInt32.Parse(ic.xml.Value);
|
result.Flags = UInt32.Parse(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "creationdate" :
|
case "creationdate" :
|
||||||
result.CreationDate = Int32.Parse(ic.xml.Value);
|
result.CreationDate = Int32.Parse(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "saletype" :
|
case "saletype" :
|
||||||
result.SaleType = Byte.Parse(ic.xml.Value);
|
result.SaleType = Byte.Parse(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
case "saleprice" :
|
case "saleprice" :
|
||||||
result.SalePrice = Int32.Parse(ic.xml.Value);
|
result.SalePrice = Int32.Parse(ic.xml.Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default :
|
default :
|
||||||
Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}",
|
Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}",
|
||||||
MsgId, ic.xml.Name, ic.xml.Value);
|
MsgId, ic.xml.Name, ic.xml.Value);
|
||||||
ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute",
|
ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute",
|
||||||
ic.xml.Name));
|
ic.xml.Name));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1793,7 +1782,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// An asset, if created is stored in the
|
/// An asset, if created is stored in the
|
||||||
/// XmlInventoryCollection
|
/// XmlInventoryCollection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
private void CollectAsset(XmlInventoryCollection ic)
|
private void CollectAsset(XmlInventoryCollection ic)
|
||||||
{
|
{
|
||||||
Rest.Log.DebugFormat("{0} Interpret asset element", MsgId);
|
Rest.Log.DebugFormat("{0} Interpret asset element", MsgId);
|
||||||
|
@ -1885,7 +1873,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
{
|
{
|
||||||
string b64string = null;
|
string b64string = null;
|
||||||
|
|
||||||
// Generate a UUID of none were given, and generally none should
|
// Generate a UUID if none were given, and generally none should
|
||||||
// be. Ever.
|
// be. Ever.
|
||||||
|
|
||||||
if (uuid == UUID.Zero)
|
if (uuid == UUID.Zero)
|
||||||
|
@ -1927,7 +1915,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
}
|
}
|
||||||
|
|
||||||
ic.Push(asset);
|
ic.Push(asset);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1935,7 +1922,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
/// This overrides the default permissions set when the
|
/// This overrides the default permissions set when the
|
||||||
/// XmlInventoryCollection object was created.
|
/// XmlInventoryCollection object was created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
private void CollectPermissions(XmlInventoryCollection ic)
|
private void CollectPermissions(XmlInventoryCollection ic)
|
||||||
{
|
{
|
||||||
if (ic.xml.HasAttributes)
|
if (ic.xml.HasAttributes)
|
||||||
|
|
Loading…
Reference in New Issue